zoukankan      html  css  js  c++  java
  • 【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]=egin{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
    ",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}
    ",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)
    ",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)
    ",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)
    ",node,l,r,L,R);
        if(L<=l&&r<=R){
            //printf("query_cnt get [%d][%d,%d]=%d
    ",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----
    ",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
    ",cow[n].x,br);
                ans[cow[n].i]=query_cnt(1,1,Y,cow[n].x,br);
                //printf("query(%d,%d)=%d
    ",cow[n].x,br,ans[cow[n].i]);
            }
        }
    
        for(int i=0;i<n;++i)printf("%d
    ",ans[i]);
    }
    TA爷的代码

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

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

  • 相关阅读:
    spring aop
    Linux进程管理命令
    逻辑卷管理-LVM(Logical Volume Manager)
    Linux磁盘与文件系统管理(二)
    Linux磁盘与文件系统管理(一)
    Linux后台运行和关闭、查看后台任务
    Linux用户管理及用户信息查询
    文件备份与压缩
    Liunx信息显示与文件搜索
    文本处理三剑客之 awk
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5776608.html
Copyright © 2011-2022 走看看