[Sdoi2008]洞穴勘測——LCT
題目描述
輝輝熱衷於洞穴勘測。某天,他按照地圖來到了一片被標記為JSZX的洞穴群地區。經過初步勘測,輝輝發現這片區域由n個洞穴(分別編號為1到n)以及若幹通道組成,並且每條通道連接了恰好兩個洞穴。假如兩個洞穴可以通過一條或者多條通道按一定順序連接起來,那麽這兩個洞穴就是連通的,按順序連接在一起的這些通道則被稱之為這兩個洞穴之間的一條路徑。洞穴都十分堅固無法破壞,然而通道不太穩定,時常因為外界影響而發生改變,比如,根據有關儀器的監測結果,123號洞穴和127號洞穴之間有時會出現一條通道,有時這條通道又會因為某種稀奇古怪的原因被毀。輝輝有一臺監測儀器可以實時將通道的每一次改變狀況在輝輝手邊的終端機上顯示:如果監測到洞穴u和洞穴v之間出現了一條通道,終端機上會顯示一條指令 Connect u v 如果監測到洞穴u和洞穴v之間的通道被毀,終端機上會顯示一條指令 Destroy u v 經過長期的艱苦卓絕的手工推算,輝輝發現一個奇怪的現象:無論通道怎麽改變,任意時刻任意兩個洞穴之間至多只有一條路徑。因而,輝輝堅信這是由於某種本質規律的支配導致的。因而,輝輝更加夜以繼日地堅守在終端機之前,試圖通過通道的改變情況來研究這條本質規律。然而,終於有一天,輝輝在堆積成山的演算紙中崩潰了……他把終端機往地面一砸(終端機也足夠堅固無法破壞),轉而求助於你,說道:“你老兄把這程序寫寫吧”。輝輝希望能隨時通過終端機發出指令 Query u v,向監測儀詢問此時洞穴u和洞穴v是否連通。現在你要為他編寫程序回答每一次詢問。已知在第一條指令顯示之前,JSZX洞穴群中沒有任何通道存在。
輸入
第一行為兩個正整數n和m,分別表示洞穴的個數和終端機上出現過的指令的個數。以下m行,依次表示終端機上出現的各條指令。每行開頭是一個表示指令種類的字符串s("Connect”、”Destroy”或者”Query”,區分大小寫),之後有兩個整數u和v (1≤u, v≤n且u≠v) 分別表示兩個洞穴的編號。
輸出
對每個Query指令,輸出洞穴u和洞穴v是否互相連通:是輸出”Yes”,否則輸出”No”。(不含雙引號)
樣例輸入
樣例輸入1 cave.inQuery 123 127
Connect 123 127
Query 123 127
Destroy 127 123
Query 123 127
樣例輸入2 cave.in
3 5
Connect 1 2
Connect 3 1
Query 2 3
Destroy 1 3
Query 2 3
樣例輸出
樣例輸出1 cave.outNo
Yes
No
樣例輸出2 cave.out
Yes
No
提示
數據說明 10%的數據滿足n≤1000, m≤20000 20%的數據滿足n≤2000, m≤40000 30%的數據滿足n≤3000, m≤60000 40%的數據滿足n≤4000, m≤80000 50%的數據滿足n≤5000, m≤100000 60%的數據滿足n≤6000, m≤120000 70%的數據滿足n≤7000, m≤140000 80%的數據滿足n≤8000, m≤160000 90%的數據滿足n≤9000, m≤180000 100%的數據滿足n≤10000, m≤200000 保證所有Destroy指令將摧毀的是一條存在的通道本題輸入、輸出規模比較大,建議c\c++選手使用scanf和printf進行I\O操作以免超時
LCT模板題,比較基礎的一道題,不需要splay維護什麽信息,只需要維護連通性即可。
#include<set> #include<map> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,m; int x,y; char ch[10]; int s[10010][2]; int f[10010]; int r[10010]; int st[10010]; int get(int rt) { return rt==s[f[rt]][1]; } void pushdown(int rt) { if(r[rt]) { r[s[rt][0]]^=1; r[s[rt][1]]^=1; r[rt]^=1; swap(s[rt][0],s[rt][1]); } } int is_root(int rt) { return rt!=s[f[rt]][0]&&rt!=s[f[rt]][1]; } void rotate(int rt) { int fa=f[rt]; int anc=f[fa]; int k=get(rt); if(!is_root(fa)) { s[anc][get(fa)]=rt; } s[fa][k]=s[rt][k^1]; f[s[fa][k]]=fa; s[rt][k^1]=fa; f[fa]=rt; f[rt]=anc; } void splay(int rt) { int top=0; st[++top]=rt; for(int i=rt;!is_root(i);i=f[i]) { st[++top]=f[i]; } for(int i=top;i>=1;i--) { pushdown(st[i]); } for(int fa;!is_root(rt);rotate(rt)) { if(!is_root(fa=f[rt])) { rotate(get(fa)==get(rt)?fa:rt); } } } void access(int rt) { for(int x=0;rt;x=rt,rt=f[rt]) { splay(rt); s[rt][1]=x; } } void reverse(int rt) { access(rt); splay(rt); r[rt]^=1; } int find(int rt) { access(rt); splay(rt); while(s[rt][0]) { rt=s[rt][0]; } return rt; } void link(int x,int y) { reverse(x); f[x]=y; } void cut(int x,int y) { reverse(x); access(y); splay(y); if(s[x][1]||f[x]!=y||s[y][get(x)^1]) { return ; } s[y][0]=f[x]=0; } int main() { scanf("%d%d",&n,&m); while(m--) { scanf("%s",ch); scanf("%d%d",&x,&y); if(ch[0]==‘Q‘) { if(find(x)!=find(y)) { printf("No\n"); } else { printf("Yes\n"); } } else if(ch[0]==‘C‘&&find(x)!=find(y)) { link(x,y); } else if(ch[0]==‘D‘&&find(x)==find(y)) { cut(x,y); } } }
[Sdoi2008]洞穴勘測——LCT