题意:
有一个n*m的网格图,q次操作:
操作有三种:
1.将一个矩形区域加上围栏
2.将一个矩形区域的围栏拆掉
3.给定两个格子的坐标,问他们直接是否存在没有围栏的路
数据范围:n,m<=2500,q<=1e5
解法:
如果两个格子之存在没有围栏的路,那么包围他们的几层围栏一定完全相同
但是操作一共1e5次,没办法记录每个格子被哪些围栏包围,时空复杂度都不够
一种办法是对围栏赋予一个随机数t,将矩形围起来等同于矩形内每个点都加上t
这样的话判断两个格子是否被相同围栏围住只需要判断两个格子的值是否相等即可
矩形赋值容易想到二维差分前缀和,因为需要动态维护,所以上二维树状数组
code:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=2500+5;
struct BIT{
ull c[N][N];
int lowbit(int i){
return i&-i;
}
void add(int x,int y,ull t){
for(int i=x;i<N;i+=lowbit(i)){
for(int j=y;j<N;j+=lowbit(j)){
c[i][j]+=t;
}
}
}
ull ask(int x,int y){
ull ans=0;
for(int i=x;i;i-=lowbit(i)){
for(int j=y;j;j-=lowbit(j)){
ans+=c[i][j];
}
}
return ans;
}
}T;
int n,m,q;
int seed1;
int seed2;
ull getrand(int x,int y,int xx,int yy){
ull ans=x*seed1+y*seed2;
ans=ans*seed1+ans*seed2+xx*seed1+yy*seed2;
ans=ans*seed2+ans*seed1;
return ans;
}
void cal(int x,int y,int xx,int yy,ull t){//二维差分
T.add(x,y,t);T.add(xx+1,yy+1,t);
T.add(x,yy+1,-t);T.add(xx+1,y,-t);
}
signed main(){
seed1=rand();//随机数种子1
seed2=rand();//随机数种子2
scanf("%d%d%d",&n,&m,&q);
while(q--){
int op,x,y,xx,yy;
x++,y++,xx++,yy++;
scanf("%d%d%d%d%d",&op,&x,&y,&xx,&yy);
if(op==1){//添加
ull t=getrand(x,y,xx,yy);
cal(x,y,xx,yy,t);
}else if(op==2){//删除
ull t=getrand(x,y,xx,yy);
cal(x,y,xx,yy,-t);
}else{//查询
ull a=T.ask(x,y);
ull b=T.ask(xx,yy);
if(a==b)puts("Yes");
else puts("No");
}
}
return 0;
}