题意:
3种操作
1 在左上角 (r1,c1)、右下角 (r2,c2) 的矩形框上设置围墙
2 把左上角 (r1,c1)、右下角 (r2,c2) 的矩形框上的围墙删掉
3 询问 (r1,c1) 能否不跨越围墙抵达 (r2,c2)
如图,两个红叉分别为 (r1,c1) (r2,c2), 粉色是它们围成的围墙,用二维树状数组维护这个网格:在棕色的四个点(r1,c1) (r1,c2+1) (r2+1,c1) (r2+1,c2+1)上打标记(单点更新一个随机值),对于每次询问,查寻(r1,c1)和(r2,c2)的二维前缀和是否相等,相等就表示它们在一个最小的矩形框内,可以互相抵达,否则不能。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=2505,MOD=1e9+7;
ull rdm[N];
ll c[N][N];
int n,m,q;
void update(int _x,int _y,int val){
for(int x=_x;x<=n;x+=x&-x) for(int y=_y;y<=m;y+=y&-y) c[x][y]+=val;
}
ll query(int _x,int _y){
ll res=0;
for(int x=_x;x;x-=x&-x) for(int y=_y;y;y-=y&-y) res+=c[x][y];
return res;
}
int main(){
srand(2333);
for(int i=1;i<=2505;++i){
rdm[i]=(rand()<<15)+rand();
rdm[i]+=(rdm[i]<<30)+(rand()<<15)+rand();
//cout<<"rdm["<<i<<"] "<<rdm[i]<<endl;
}
scanf("%d%d%d",&n,&m,&q);
n++;m++;
while(q--){
int op,r1,c1,r2,c2;//左上 右下
scanf("%d%d%d%d%d",&op,&r1,&c1,&r2,&c2);
int hsh=(rdm[r1]*13+rdm[c1]*53+rdm[r2]*17+rdm[c2]*15)%MOD;//产生随机数
if(op==1) update(r1,c1,hsh),update(r1,c2+1,-hsh),update(r2+1,c1,-hsh),update(r2+1,c2+1,hsh);else
if(op==2) update(r1,c1,-hsh),update(r1,c2+1,hsh),update(r2+1,c1,hsh),update(r2+1,c2+1,-hsh);else
if(query(r1,c1)==query(r2,c2)) puts("Yes");else puts("No");
}
}
PS:Hash的方法学习一下
参考博客:
[哈希+差分] Codeforces 869E. The Untended Antiquity
扩展:树状数组+差分 处理 矩形覆盖 好像是个套路