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

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]$

这样DP的时间复杂度是$O((N+F+M)^{2})$的

那么考虑优化这个DP

差分出$f[i][j]$表示$(i,j)$能得到,但$(i,j-1)$不能得到的花的数量

那么考虑扫描线,从右往左

那讨论一下各种情况,

遇到花单点数值+1;遇到一个未出现过的栅栏,区间查询和,单点修改数值,区间修改覆盖0;删除一个栅栏,区间修改覆盖0;遇见一头牛,找到下方第一个栅栏,区间求和;

显然都可以用线段树维护

查找下方第一个栅栏?维护一个最小即可

时间复杂度是$O(10^{6}log10^{6})$

实现起来有一些细节,线段树中需要加特判,当所需要修改的坐标为0啊之类的

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; 
}
#include<cstdio>
#include<iostream>
using namespace std;
#include<cstring>
#include<cmath>
#include<algorithm>
const int X=1e6+5,Y=1e6,F=2e5+5,M=2e5+5,N=2e5+5;
char * cp=(char *)malloc(20000000);
void in(int &x){
    while(*cp<'0'||*cp>'9')++cp;
    for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0');
}

struct FenS{    
    int xl,xr;
    int y;
    int i;
    bool flag;
    bool operator < (const FenS & o)const{
        return y!=o.y?y>o.y:xl<o.xl;
    }
}fence[F<<1];
int fsum[F];
struct FloS{
    int x,y;
    bool operator < (const FloS & o)const{
        return y>o.y;
    }
}flower[M];
struct CS{
    int x,y;
    int i;
    bool operator < (const CS & o)const{
        return y>o.y;
    }
}cow[N];
int ans[N];

struct SS{
    int cnt;
    bool cover;
    bool barrier;
}segt[X<<2];
#define lson node<<1,l,l+r>>1
#define rson node<<1|1,(l+r>>1)+1,r
void out(int node,int l,int r){
    printf("segt[%d][%d,%d]={cnt=%d,cover=%d,barrier=%d}\n",node,l,r,segt[node].cnt,segt[node].cover,segt[node].barrier);
}
void pushup(int node){
    segt[node].cnt=segt[node<<1].cnt+segt[node<<1|1].cnt;
    segt[node].barrier=segt[node<<1].barrier|segt[node<<1|1].barrier;
}
void paint(int node){
    //printf("paint(%d)\n",node);
    segt[node].cover=1;
    segt[node].cnt=0;
}
void pushdown(int node){
    if(segt[node].cover){
        paint(node<<1),paint(node<<1|1);
        segt[node].cover=0;
    }
}
void add(int node,int l,int r,int x,int delta){
    //printf("add(%d,%d,%d,%d,%d)\n",node,l,r,x,delta);
    //out(node,l,r);
    segt[node].cnt+=delta;
    if(l!=r){
        pushdown(node);
        if(x<=l+r>>1)add(lson,x,delta);
        else add(rson,x,delta);
        pushup(node);
    }
    //printf("add:");
    //out(node,l,r);
}
void cover(int node,int l,int r,int L,int R){
    //out(node,l,r);
    if(L<=l&&r<=R)paint(node);
    else{
        pushdown(node);
        if(L<=l+r>>1)cover(lson,L,R);
        if(R>l+r>>1)cover(rson,L,R);
        pushup(node);
    }
}
int query_cnt(int node,int l,int r,int L,int R){
    //printf("query(%d,%d,%d,%d,%d)\n",node,l,r,L,R);
    if(L<=l&&r<=R){
        //printf("query_cnt get [%d][%d,%d]=%d\n",node,l,r,segt[node].cnt);
        return segt[node].cnt;
    }
    else{
        pushdown(node);
        int ans=0;
        if(L<=l+r>>1)ans+=query_cnt(lson,L,R);
        if(R>l+r>>1)ans+=query_cnt(rson,L,R);
        return ans;
    }
}
void update(int node,int l,int r,int x){
    if(l==r)segt[node].barrier^=1;
    else{
        pushdown(node);
        if(x<=l+r>>1)update(lson,x);
        else update(rson,x);
        pushup(node);
    }
    //printf("update:");
    //out(node,l,r);
}
int query_barrier(int node,int l,int r,int L){
    if(l>=L){
        //printf("Query_barrier Get ");
        //out(node,l,r);
        if(segt[node].barrier){
            while(l!=r)
                if(segt[node<<1].barrier)node<<=1,r=l+r>>1;
                else node=node<<1|1,l=(l+r>>1)+1;
            return l;
        }
        else return 0;
    }
    else{
        int tmp;
        pushdown(node);
        if(L<=l+r>>1&&(tmp=query_barrier(lson,L)))return tmp;
        else return query_barrier(rson,L);
    }
}
int main(){
    freopen("cow.in","r",stdin);
    freopen("cow.out","w",stdout);
    fread(cp,1,20000000,stdin);
    int f;
    in(f);
    int x1,y1,x2,y2;
    for(int i=f;i--;){
        in(x1),in(y1),in(x2),in(y2);
        fence[i<<1]=(FenS){x1,x2,y1-1,i,0};
        fence[i<<1|1]=(FenS){x1,x2,y2,i,1};
    }
    sort(fence,fence+(f<<1));
    int m;
    in(m);
    for(int i=m;i--;)in(flower[i].x),in(flower[i].y);
    sort(flower,flower+m);
    int n;
    in(n);
    for(int i=0;i<n;++i){
        in(cow[i].x),in(cow[i].y);
        cow[i].i=i;
    }
    sort(cow,cow+n);

    f=m=n=0;
    update(1,1,Y,Y);
    int sum,br;
    for(int i=Y;i;--i){
        //printf("----%d----\n",i);
        for(;fence[f].y==i;++f)
            if(fence[f].flag==0){
                cover(1,1,Y,fence[f].xl,fence[f].xr);
                if(fence[f].xl!=1)add(1,1,Y,fence[f].xl-1,-fsum[fence[f].i]);

                if(fence[f].xl!=1)update(1,1,Y,fence[f].xl-1);
                if(fence[f].xr!=Y)update(1,1,Y,fence[f].xr);
            }
            else{
                br=query_barrier(1,1,Y,fence[f].xr);
                sum=query_cnt(1,1,Y,fence[f].xl,fence[f].xr);
                fsum[fence[f].i]=query_cnt(1,1,Y,fence[f].xr+1,br);
                cover(1,1,Y,fence[f].xl,fence[f].xr);
                if(fence[f].xl>1)add(1,1,Y,fence[f].xl-1,sum+fsum[fence[f].i]);

                if(fence[f].xl!=1)update(1,1,Y,fence[f].xl-1);
                if(fence[f].xr!=Y)update(1,1,Y,fence[f].xr);
            }
        for(;flower[m].y==i;++m){
            //cout<<flower[m].x<<","<<flower[m].y<<endl;
            add(1,1,Y,flower[m].x,1);
        }
        for(;cow[n].y==i;++n){
            br=query_barrier(1,1,Y,cow[n].x);
            //printf("br(%d)=%d\n",cow[n].x,br);
            ans[cow[n].i]=query_cnt(1,1,Y,cow[n].x,br);
            //printf("query(%d,%d)=%d\n",cow[n].x,br,ans[cow[n].i]);
        }
    }

    for(int i=0;i<n;++i)printf("%d\n",ans[i]);
}
TA爷的代码

 TA爷的模拟赛.....暴力都没写.....有点对不起TA爷....(不过似乎当时这题没得分的?)

自己的代码比较丑,这里附上当时TA爷的std,供参考

posted @ 2016-08-16 15:34  DaD3zZ  阅读(998)  评论(0编辑  收藏  举报