XSY原創題 柵欄
阿新 • • 發佈:2018-11-03
題目大意
給定一個$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; }