码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ-4422】Cow Confinement 线段树 + 扫描线 + 差分 (优化DP)

时间:2016-08-16 16:02:47      阅读:466      评论:0      收藏:0      [点我收藏+]

标签:

4422: [Cerc2015]Cow Confinement

Time Limit: 50 Sec  Memory Limit: 512 MB
Submit: 61  Solved: 26
[Submit][Status][Discuss]

Description

一个10^6行10^6列的网格图,上面有一些牛、花和一些矩形围栏,围栏在格子的边界上,牛和花在格子里,牛只能向下或向右走,牛也不能穿过围栏和地图边界,求每头牛它能到达的花的数量。注意栅栏不会相交
 
 技术分享

Input

第一行一个数f表示矩形围栏的数量。
接下来f行,每行四个数x1,y1,x2,y2,表示(x1,y1)在围栏内部矩形的左上角,(x2,y2)在右下角。
接下来一行一个数m表示花的数量。
接下来m行每行两个数x,y,表示在(x,y)处有一朵花。
接下来一行一个数n表示牛的数量。
接下来n行每行两个数x,y,表示在(x,y)处有一头牛。

Output

总共n行,每行一个数ans,第i个数表示第i头牛能到ans个花。

Sample Input

4
2 2 8 4
1 9 4 10
6 7 9 9
3 3 7 3
9
3 4
8 4
11 5
10 7
10 8
9 8
2 8
4 11
9 11
8
1 1
5 10
6 9
3 7
7 1
4 2
7 5
3 3

Sample Output

5
1
0
1
3
1
3
0

HINT

0<=f<=200000
0<=m<=200000
1<=n<=200000

Source

Solution

一道idea非常好的题

首先这题可以DP,不过转移之类的需要讨论,比较麻烦

$dp[i][j]=\begin{Bmatrix} 0(下面和右面都有栅栏)\\ dp[i+1][j](右面有栅栏)\\ dp[i][j+1](下面有栅栏)\\ dp[i+1][j]+dp[i][j+1]-dp[i+1][j+1]((i+1,j+1)不是栅栏的左上角)\\ dp[i+1][j]+dp[i][j+1]-dp[x+1][y+1]((i+1,j+1)是左上角,(x,y)是右下角)& & \end{Bmatrix}+flower[i][j]$

Code

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cstring> 
#include<cmath> 
using namespace std; 
inline int read() 
{ 
    int x=0,f=1; char ch=getchar(); 
    while (ch<0 || ch>9) {if (ch==-) f=-1; ch=getchar();} 
    while (ch>=0 && ch<=9) {x=x*10+ch-0; ch=getchar();} 
    return x*f; 
} 
#define MAXY 1000000 
#define MAXF 200010 
#define MAXN 200010 
#define MAXM 200010 
int F,M,N; 
struct FenceNode{int x1,x2,y1,y2;}fen[MAXF]; 
struct CowNode{int x,y,id;}cow[MAXN]; 
struct FlowerNode{int x,y;}flo[MAXM]; 
struct LineNode{int y,x1,x2,id,f;}line[MAXF<<1];  int tp; 
struct SegmentTreeNode{int l,r,tag,bk,sum;}tree[MAXY<<2]; 
int tmp[MAXF],ans[MAXN]; 
inline void Update(int now) 
{ 
    tree[now].bk=min(tree[now<<1].bk,tree[now<<1|1].bk); 
    tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum; 
} 
inline void PushDown(int now) 
{ 
    if (!tree[now].tag || tree[now].l==tree[now].r) return; 
    tree[now].tag=0; 
    tree[now<<1].sum=0; tree[now<<1|1].sum=0; 
    tree[now<<1].tag=1; tree[now<<1|1].tag=1;  
} 
inline void BuildTree(int now,int l,int r)  
{ 
    tree[now].l=l,tree[now].r=r; 
    tree[now].sum=0; tree[now].tag=0; tree[now].bk=MAXY; 
    if (l==r) return; 
    int mid=(l+r)>>1; 
    BuildTree(now<<1,l,mid); 
    BuildTree(now<<1|1,mid+1,r); 
    Update(now); 
} 
inline void PointChangeSum(int now,int pos,int D) 
{ 
    if (pos==MAXY+1 || pos==0) return;
    int l=tree[now].l,r=tree[now].r; 
    PushDown(now); 
    if (l==r) {tree[now].sum+=D; return;} 
    int mid=(l+r)>>1; 
    if (pos<=mid) PointChangeSum(now<<1,pos,D); 
    if (pos>mid) PointChangeSum(now<<1|1,pos,D); 
    Update(now); 
} 
inline void PointChangeBreak(int now,int pos,int D) 
{ 
    if (pos==MAXY+1 || pos==0) return;
    int l=tree[now].l,r=tree[now].r; 
    PushDown(now); 
    if (l==r) {tree[now].bk=D? l:MAXY; return;} 
    int mid=(l+r)>>1; 
    if (pos<=mid) PointChangeBreak(now<<1,pos,D); 
    if (pos>mid) PointChangeBreak(now<<1|1,pos,D); 
    Update(now); 
} 
inline void IntervalChange(int now,int L,int R) 
{ 
    if (L==0 || R==MAXY+1 || R<L) return;
    int l=tree[now].l,r=tree[now].r; 
    PushDown(now); 
    if (L<=l && R>=r) {tree[now].tag=1; tree[now].sum=0; return;} 
    int mid=(l+r)>>1; 
    if (L<=mid) IntervalChange(now<<1,L,R); 
    if (R>mid) IntervalChange(now<<1|1,L,R); 
    Update(now); 
} 
inline int IntervalQuerySum(int now,int L,int R) 
{ 
    if (L==0 || R==MAXY+1 || R<L) return 0;
    int l=tree[now].l,r=tree[now].r; 
    PushDown(now); 
    if (L<=l && R>=r) return tree[now].sum; 
    int mid=(l+r)>>1,re=0; 
    if (L<=mid) re+=IntervalQuerySum(now<<1,L,R); 
    if (R>mid) re+=IntervalQuerySum(now<<1|1,L,R); 
    return re; 
} 
inline int IntervalQueryBreak(int now,int L,int R)
{
    if (L==0 || R==MAXY+1 || R<L) return 0;
    int l=tree[now].l,r=tree[now].r;
    PushDown(now);
    if (L<=l && R>=r) return tree[now].bk;
    int mid=(l+r)>>1,re=MAXY;
    if (L<=mid) re=min(re,IntervalQueryBreak(now<<1,L,R));
    if (R>mid) re=min(re,IntervalQueryBreak(now<<1|1,L,R));
    return re;
}
inline bool cmpLine(LineNode A,LineNode B) {return A.y!=B.y? A.y>B.y : A.x1<B.x1;} 
inline bool cmpCow(CowNode A,CowNode B) {return A.y>B.y;} 
inline bool cmpFlower(FlowerNode A,FlowerNode B) {return A.y>B.y;} 
int main() 
{ 
    F=read(); 
    for (int i=1; i<=F; i++) fen[i].x1=read(),fen[i].y1=read(),fen[i].x2=read(),fen[i].y2=read(); 
    for (int i=1; i<=F; i++)  
        line[++tp]=(LineNode){fen[i].y1-1,fen[i].x1,fen[i].x2,i,-1}, 
        line[++tp]=(LineNode){fen[i].y2,fen[i].x1,fen[i].x2,i,1}; 
    sort(line+1,line+tp+1,cmpLine); 
    M=read(); 
    for (int i=1; i<=M; i++) flo[i].x=read(),flo[i].y=read(); 
    sort(flo+1,flo+M+1,cmpFlower); 
    N=read(); 
    for (int i=1; i<=N; i++) cow[i].x=read(),cow[i].y=read(),cow[i].id=i; 
    sort(cow+1,cow+N+1,cmpCow); 
    BuildTree(1,1,MAXY); 
    int nowl=1,nowf=1,nowc=1,next,sum; 
    for (int i=MAXY; i; i--) 
        { 
            while (line[nowl].y==i) 
                { 
                    if (line[nowl].f==-1) 
                        { 
                            IntervalChange(1,line[nowl].x1,line[nowl].x2); 
                            PointChangeSum(1,line[nowl].x1-1,-tmp[line[nowl].id]); 
                            PointChangeBreak(1,line[nowl].x1-1,0); 
                            PointChangeBreak(1,line[nowl].x2,0); 
                        } 
                    else
                        { 
                            next=IntervalQueryBreak(1,line[nowl].x2,MAXY); 
                            sum=IntervalQuerySum(1,line[nowl].x1,line[nowl].x2); 
                            tmp[line[nowl].id]=IntervalQuerySum(1,line[nowl].x2+1,next); 
                            IntervalChange(1,line[nowl].x1,line[nowl].x2); 
                            PointChangeSum(1,line[nowl].x1-1,sum+tmp[line[nowl].id]); 
                            PointChangeBreak(1,line[nowl].x1-1,1); 
                            PointChangeBreak(1,line[nowl].x2,1); 
                        } 
                    nowl++; 
                } 
            while (flo[nowf].y==i) 
                PointChangeSum(1,flo[nowf].x,1),nowf++; 
            while (cow[nowc].y==i) 
                next=IntervalQueryBreak(1,cow[nowc].x,MAXY), 
                ans[cow[nowc].id]=IntervalQuerySum(1,cow[nowc].x,next), 
                nowc++; 
        } 
    for (int i=1; i<=N; i++) printf("%d\n",ans[i]); 
    return 0; 
}

 

【BZOJ-4422】Cow Confinement 线段树 + 扫描线 + 差分 (优化DP)

标签:

原文地址:http://www.cnblogs.com/DaD3zZ-Beyonder/p/5776608.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!