BZOJ1018:[SHOI2008]堵塞的交通
阿新 • • 發佈:2018-11-14
淺談樹狀陣列與線段樹:https://www.cnblogs.com/AKMer/p/9946944.html
題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=1018
我們把第一行和第二行的城市一起處理,對於每一個區間[\(l,r\)]的城市,我們需要維護下面六種關係:
一共六條邊,分別用\(bool\)型別的六個變數來表示這六種聯通關係是否成立。
然後詢問兩個城市是否聯通,也許他們會繞出區間[\(l,r\)]再繞回來然後聯通,所以有四種路徑可以走;假設我詢問的是一號城市和三號城市,二號城市是一號城市上方/下方的城市,四號城市是三號城市上方/下方的城市,那麼這四條路徑分別是:
一號---->三號(紅色)
一號----》二號---->三號(綠色)
一號---->四號----》三號(藍色)
一號----》二號---->四號----》三號(灰色)
其中>表示在區間內,》表示繞出去,如圖所示:
時間複雜度:\(O(nlong)\)
空間複雜度:\(O(n)\)
程式碼如下:
#include <cstdio> #include <algorithm> using namespace std; const int maxn=1e5+5; int n; char s[10]; bool bo[maxn*3];//bo數組裡,[1,n-1]存的是第一行的道路,[n,2*n-1]存的是每一列的道路,[2*n,3*n-2]存的是第二行的道路。 int read() { int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0'; return x*f; } struct tree_node { bool a1,a2,a3,a4,a5,a6; }; struct segment_tree { tree_node tree[maxn<<2]; tree_node merge(tree_node f,tree_node g,int mid) { tree_node res;int mid1=mid,mid2=mid+2*n-1; res.a1=(f.a1)|(f.a2&&bo[mid1]&&g.a1&&bo[mid2]&&f.a4); //f.a2&&bo[mid1]&&g.a1&&bo[mid2]&&f.a4 1號路徑 //f.a5&&bo[mid2]&&g.a1&&bo[mid1]&&f.a6 2號路徑 //如果2號路徑存在那麼1號路徑必然存在,所以只需要判1號路徑即可 res.a2=(f.a2&&bo[mid1]&&g.a2)|(f.a5&&bo[mid2]&&g.a6); res.a3=(g.a3)|(g.a2&&bo[mid1]&&f.a3&&bo[mid2]&&g.a4); res.a4=(f.a4&&bo[mid2]&&g.a4)|(f.a6&&bo[mid1]&&g.a5); res.a5=(f.a2&&bo[mid1]&&g.a5)|(f.a5&&bo[mid2]&&g.a4); res.a6=(f.a4&&bo[mid2]&&g.a6)|(f.a6&&bo[mid1]&&g.a2); return res; } void build(int p,int l,int r) { if(l==r) { tree[p].a2=tree[p].a4=1; return; } int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); } void change(int p,int l,int r,int L,int R) { if(l==r) { if(L==R) { tree[p].a1^=1; tree[p].a3^=1; tree[p].a5^=1; tree[p].a6^=1;//如果是單點修改那麼這四種關係應該改變狀態 } return; } int mid=(l+r)>>1; if(L<=mid)change(p<<1,l,mid,L,R); else change(p<<1|1,mid+1,r,L,R); tree[p]=merge(tree[p<<1],tree[p<<1|1],mid); } tree_node query(int p,int l,int r,int L,int R) { if(L<=l&&r<=R)return tree[p]; int mid=(l+r)>>1;tree_node res; if(R<=mid)res=query(p<<1,l,mid,L,R); else if(L>mid)res=query(p<<1|1,mid+1,r,L,R); else res=merge(query(p<<1,l,mid,L,R),query(p<<1|1,mid+1,r,L,R),mid); return res; } }T; int main() { n=read();T.build(1,1,n); while(~scanf("%s",s+1)) { if(s[1]=='E')break; int x1=read(),y1=read(),x2=read(),y2=read(); if(y1>y2)swap(y1,y2),swap(x1,x2); if(s[1]=='O'||s[1]=='C') { if(x1==x2) { int tmp=y1; if(x1==2)tmp+=2*n-1; bo[tmp]^=1;T.change(1,1,n,y1,y2); } else { bo[y1+n-1]^=1; T.change(1,1,n,y1,y2); } } else { bool ans=0; tree_node j=T.query(1,1,n,1,y1); tree_node k=T.query(1,1,n,y1,y2); tree_node l=T.query(1,1,n,y2,n); if(x1==x2) { if(x1==1) { ans|=k.a2; ans|=j.a3&&k.a6; ans|=k.a5&&l.a1; ans|=j.a3&&k.a4&&l.a1; } else { ans|=k.a4; ans|=j.a3&&k.a5; ans|=k.a6&&l.a1; ans|=j.a3&&k.a2&&l.a1; } } else { if(x1==1) { ans|=k.a5; ans|=j.a3&&k.a4; ans|=k.a2&&l.a1; ans|=j.a3&&k.a6&&l.a1; } else { ans|=k.a6; ans|=j.a3&&k.a2; ans|=k.a4&&l.a1; ans|=j.a3&&k.a5&&l.a1; } }//對於詢問的兩個點的位置一共有四種不同的關係,分別分情況討論 if(ans)puts("Y"); else puts("N"); } } return 0; }