1. 程式人生 > >XSY原創題 柵欄

XSY原創題 柵欄

題目大意

給定一個$n\times m$的網格圖,每次會選擇一塊矩形沿著網格線鋪上柵欄,或者拆除之前鋪的柵欄,或者詢問兩個格子能否不經過柵欄直接到達。

保證柵欄沒有重疊或交叉,刪去的柵欄刪除前一定存在。

 

題解

考慮兩個格子能互相到達,當且僅當包含它們的柵欄完全相同。考慮對每一個柵欄隨機一個權值,維護覆蓋每個點的所有柵欄的異或和。

詢問兩個點時,若兩個點權值不相同,那麼一定不在。否則,可以直接認為覆蓋它們的柵欄集合完全相同。

由於在$MaxInt$範圍內隨機權值,那麼一共會出現$2^30$種權值異或和,幾乎已經不可能出現重合。也可以用多次隨機和擴大權值範圍來增大正確率。

至於矩形異或,維護一個點的權值,可以直接使用差分$+$二維樹狀陣列。

複雜度$O(Q\log n\log m)$。

#include<bits/stdc++.h>
#define debug(x) cerr<<#x<<" = "<<x
#define sp <<"  "
#define el <<endl
#define LL long long
#define N 2020
#define M 100020
#define pii pair<int,int>
#define mp make_pair
using namespace std;
int read(){
	int nm=0,fh=1; char cw=getchar();
	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
	return nm*fh;
}
int n,m,nt[M],bf[M],tot,c[N][N],p[M]; map<pii,int> MP;
int rd(){return (rand()<<13)^rand();}
inline void ins(int x,int y,LL dt){
	for(int k1=x;k1<=n;k1=nt[k1]) for(int k2=y;k2<=m;k2=nt[k2]) c[k1][k2]^=dt;
}
inline LL qry(int x,int y){
	LL tt=0;
	for(int k1=x;k1;k1=bf[k1]) for(int k2=y;k2;k2=bf[k2]) tt^=c[k1][k2];
	return tt;
}
#define add(x,y,xx,yy,dt) ins(x,y,dt),ins(x,yy+1,dt),ins(xx+1,y,dt),ins(xx+1,yy+1,dt)
int main(){
	srand(19260817); n=read(),m=read();
	for(int i=1;i<=max(n,m);i++) nt[i]=i+(i&-i),bf[i]=i-(i&-i);
	for(int tpe,t1,t2,t3,t4,id,T=read();T;T--){
		tpe=read(),t1=read(),t2=read(),t3=read(),t4=read();
		if(tpe==1){MP[mp(t1,t2)]=++tot,p[tot]=rd(),add(t1,t2,t3,t4,p[tot]);}
		else if(tpe==2){id=MP[mp(t1,t2)];add(t1,t2,t3,t4,p[id]);}
		else{bool fg=(qry(t1,t2)==qry(t3,t4));puts(fg?"Yes":"No");}
	}
	return 0;
}