给定 n × m n\times m n×m 的空地,支持加围栏,去围栏,询问两点是否在连通块内。 n , m ≤ 2500 n,m\leq 2500 n,m≤2500 , q ≤ 1 0 5 q\leq 10^5 q≤105 。
题目中的询问两点是否连通相当于询问两点被包含的墙是否相等,以样例图为例
所以只用维护每个点被包含的区间即可。但 q q q 到达 1 0 5 10^5 105 级别,暴力比对肯定不行,用哈希的思想来维护。具体来说,对于每一个矩形维护一个哈希值,用树状数组维护前缀和单点修改,同时对于每次查询,只要对应值相等则为连通。(需要找一个不好卡的哈希算法,否则容易被卡)
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define lowbit(x) x&(-x)
map < pair< pii , pii > , int > M;
int n,m,q;
int a[2505][2505];
void add(int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
a[i][j]+=z;
}
int get(int x,int y)
{
int ans=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
ans+=a[i][j];
return ans;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
while(q--){
int op,r1,c1,r2,c2;
scanf("%d %d %d %d %d",&op,&r1,&c1,&r2,&c2);
int x=r1*1327+c1*382-r2+c2*c2;
if(op==1){
add(r1,c1,x);add(r2+1,c2+1,x);
add(r2+1,c1,-x);add(r1,c2+1,-x);
}
else if(op==2){
x=-x;
add(r1,c1,x);add(r2+1,c2+1,x);
add(r2+1,c1,-x);add(r1,c2+1,-x);
}
else{
int v1=get(r1,c1);
int v2=get(r2,c2);
printf("%s\n",(v1==v2)?"Yes":"No");
}
}
return 0;
}