【Codeforces 575I】Robots protection

CDQ 分治。

题目大意:

给定 $n\times n$ 的矩形,有两种操作:

  1. 让一个等腰直角三角形的区域的点的值加一。
  2. 询问一个点的值。

题解:

如果是矩形区域则很容易使用二维数据结构/CDQ 分治维护。

考虑把三角形看成一个平行四边形的一部分,并且右端点无限延伸。平行四边形区域的加法是可以像矩形一样维护的,分两种不同方向讨论即可。

考虑减去多余的贡献。减去多余的那部分,相当于减去一个矩形区域(都是无限延伸的)。这个也可以维护。

因此对三种四边形使用 CDQ 分治或者树套树维护即可。

时间复杂度 $O(q\log q\log n)$(CDQ 分治)或 $O(q\log^2 n)$(树套树)。

Code:

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=18888;
int n,m;
struct fwt{
    int b[M];
    inline void add(int i,int x){for(;i<M;i+=i&-i)b[i]+=x;}
    inline int ask(int i){int x=0;for(;i;i&=i-1)x+=b[i];return x;}
    inline void modify(int l,int r,const int&x){add(l,x),add(r+1,-x);}
}B[3];
int ans[N],k;
struct que{
    int op,x,l,r,id;
    inline bool operator<(const que&rhs)const{return x<rhs.x;}
}A[N*4],tmp[N*4];// | 0  / 1  \ 2
void solve(int l,int r){
    if(l>=r)return;
    const int mid=l+r>>1;
    for(int i=l;i<=r;++i)tmp[i]=A[i];
    sort(tmp+l,tmp+mid+1);
    sort(tmp+mid+1,tmp+r+1);
    int L=l,R=mid+1;
    while(L<=mid&&R<=r)
    if(tmp[L].x<=tmp[R].x){
        if(tmp[L].op<3)B[tmp[L].op].modify(tmp[L].l,tmp[L].r,tmp[L].id);
        ++L;
    }else{
        if(tmp[R].op==3){
            int y=tmp[R].r,x=tmp[R].x;
            ans[tmp[R].id]+=B[0].ask(y)+B[1].ask(x+y)+B[2].ask(y-x+n);
        }
        ++R;
    }
    for(;R<=r;++R)
    if(tmp[R].op==3){
        int y=tmp[R].r,x=tmp[R].x;
        ans[tmp[R].id]+=B[0].ask(y)+B[1].ask(x+y)+B[2].ask(y-x+n);
    }
    for(int i=l;i<L;++i)
    if(tmp[i].op<3)B[tmp[i].op].modify(tmp[i].l,tmp[i].r,-tmp[i].id);
    solve(l,mid);
    solve(mid+1,r);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        ans[i]=-1;
        int op;
        scanf("%d",&op);
        if(op==1){
            int dir,x,y,len;
            scanf("%d%d%d%d",&dir,&x,&y,&len);
            switch(dir){
                case 1:{
                    A[++k]=(que){0,x,1,y-1,-1},A[++k]=(que){0,x+len+1,1,y-1,1};
                    A[++k]=(que){1,x,1,x+y+len,1},A[++k]=(que){1,x+len+1,1,x+y+len,-1};
                    break;
                }
                case 2:{
                    A[++k]=(que){0,x,y+1,n,-1},A[++k]=(que){0,x+len+1,y+1,n,1};
                    A[++k]=(que){2,x,y-x+n-len,2*n,1},A[++k]=(que){2,x+len+1,y-x+n-len,2*n,-1};
                    break;
                }
                case 3:{
                    A[++k]=(que){0,x-len,1,y-1,-1},A[++k]=(que){0,x+1,1,y-1,1};
                    A[++k]=(que){2,x-len,1,y-x+n+len,1},A[++k]=(que){2,x+1,1,y-x+n+len,-1};
                    break;
                }
                case 4:{
                    A[++k]=(que){0,x-len,y+1,n,-1},A[++k]=(que){0,x+1,y+1,n,1};
                    A[++k]=(que){1,x-len,x+y-len,2*n,1},A[++k]=(que){1,x+1,x+y-len,2*n,-1};
                    break;
                }
            }
        }else{
            int x,y;
            scanf("%d%d",&x,&y);
            ans[i]=0;
            A[++k]=(que){3,x,y,y,i};
        }
    }
    solve(1,k);
    for(int i=1;i<=m;++i)
    if(ans[i]!=-1)printf("%d\n",ans[i]);
    return 0;
}