Description
辉辉热衷于洞穴勘测。某天,他按照地图来到了一片被标记为JSZX的洞穴群地区。经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴。假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些通道则被称之为这两个洞穴之间的一条路径。洞穴都十分坚固无法破坏,然而通道不太稳定,时常因为外界影响而发生改变,比如,根据有关仪器的监测结果,123号洞穴和127号洞穴之间有时会出现一条通道,有时这条通道又会因为某种稀奇古怪的原因被毁。辉辉有一台监测仪器可以实时将通道的每一次改变状况在辉辉手边的终端机上显示:如果监测到洞穴u和洞穴v之间出现了一条通道,终端机上会显示一条指令 Connect u v 如果监测到洞穴u和洞穴v之间的通道被毁,终端机上会显示一条指令 Destroy u v 经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。因而,辉辉坚信这是由于某种本质规律的支配导致的。因而,辉辉更加夜以继日地坚守在终端机之前,试图通过通道的改变情况来研究这条本质规律。然而,终于有一天,辉辉在堆积成山的演算纸中崩溃了……他把终端机往地面一砸(终端机也足够坚固无法破坏),转而求助于你,说道:“你老兄把这程序写写吧”。辉辉希望能随时通过终端机发出指令 Query u v,向监测仪询问此时洞穴u和洞穴v是否连通。现在你要为他编写程序回答每一次询问。已知在第一条指令显示之前,JSZX洞穴群中没有任何通道存在。
Input
第一行为两个正整数n和m,分别表示洞穴的个数和终端机上出现过的指令的个数。
以下m行,依次表示终端机上出现的各条指令。每行开头是一个表示指令种类的字符串s("Connect”、”Destroy”或者”Query”,区分大小写),之后有两个整数u和v (1≤u, v≤n且u≠v) 分别表示两个洞穴的编号。
Output
对每个Query指令,输出洞穴u和洞穴v是否互相连通:是输出”Yes”,否则输出”No”。(不含双引号)
Sample Input
样例输入1 cave.in
200 5
Query 123 127
Connect 123 127
Query 123 127
Destroy 127 123
Query 123 127
200 5
Query 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
Sample Output
样例输出1 cave.out
No
Yes
No
No
Yes
No
样例输出2 cave.out
Yes
No
HINT
数据说明
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指令将摧毁的是一条存在的通道
本题输入、输出规模比较大,建议cc++选手使用scanf和printf进行IO操作以免超时
Source
Solution
数据辣么有节奏感是什么鬼啦~
还有带删除并查集的姿势是什么鬼啦~
反正就是LCT搞一搞。连边就是link(x, y),删边就是cut(x, y),查询就是看find_root(x)是否等于find_root(y)。
然后还有些splay函数access函数什么的就不用说了。
第一道LCT的题,好像写+调试共用40分钟。。。好慢。。。
常数大得飞起QAQ
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct LCT 4 { 5 int c[2], fa, rev; 6 int& operator [] (int i) 7 { 8 return c[i]; 9 } 10 }a[10005]; 11 int top, sta[10005]; 12 13 void scanf(int &x) 14 { 15 char ch = getchar(); 16 x = 0; 17 while(ch < '0' || ch > '9') 18 ch = getchar(); 19 while(ch >= '0' && ch <= '9') 20 x = x * 10 + ch - 48, ch = getchar(); 21 } 22 23 void push_down(int k) 24 { 25 if(a[k].rev) 26 { 27 a[a[k][0]].rev ^= 1, a[a[k][1]].rev ^= 1; 28 swap(a[k][0], a[k][1]), a[k].rev = 0; 29 } 30 } 31 32 bool isroot(int x) 33 { 34 return a[a[x].fa][0] != x && a[a[x].fa][1] != x; 35 } 36 37 void rotate(int x) 38 { 39 int y = a[x].fa, z = a[y].fa; 40 int dy = a[y][1] == x, dz = a[z][1] == y; 41 if(!isroot(y)) a[z][dz] = x; 42 a[y][dy] = a[x][dy ^ 1], a[a[x][dy ^ 1]].fa = y; 43 a[x][dy ^ 1] = y, a[y].fa = x, a[x].fa = z; 44 } 45 46 void splay(int x) 47 { 48 sta[top = 1] = x; 49 for(int i = x; !isroot(i); i = a[i].fa) 50 sta[++top] = a[i].fa; 51 while(top) 52 push_down(sta[top--]); 53 while(!isroot(x)) 54 { 55 int y = a[x].fa, z = a[y].fa; 56 if(!isroot(y)) 57 if(a[y][1] == x ^ a[z][1] == y) rotate(x); 58 else rotate(y); 59 rotate(x); 60 } 61 } 62 63 void access(int x) 64 { 65 for(int i = 0; x; x = a[x].fa) 66 splay(x), a[x][1] = i, i = x; 67 } 68 69 void make_root(int x) 70 { 71 access(x), splay(x), a[x].rev ^= 1; 72 } 73 74 void link(int x, int y) 75 { 76 make_root(x), a[x].fa = y; 77 } 78 79 void cut(int x, int y) 80 { 81 make_root(x), access(y), splay(y), a[y][0] = a[x].fa = 0; 82 } 83 84 int find_root(int x) 85 { 86 access(x), splay(x); 87 while(a[x][0]) 88 x = a[x][0]; 89 return x; 90 } 91 92 int main() 93 { 94 int n, m, x, y; 95 char op[10]; 96 scanf("%d%d", &n, &m); 97 while(m--) 98 { 99 scanf("%s", op); 100 scanf(x), scanf(y); 101 if(op[0] == 'C') link(x, y); 102 else if(op[0] == 'D') cut(x, y); 103 else puts(find_root(x) == find_root(y) ? "Yes" : "No"); 104 } 105 return 0; 106 }