1.并查集骗分(数据太水,比正解还快。。。)
我们知道,并查集有一步操作叫“路径压缩”,但是本题的并查集我们不能路径压缩,否则就无法进行Destroy操作。那每一步操作我们应该怎么做呢?
对于Connect x y操作,先把x变成集合的根,之后root[x] = y;
对于Destroy x y操作,先把x变成集合的根,此时root[y]必然为x,令root[y] = y即可。
对于Query x y操作,看看x和y所在集合的根是不是一样的就好了。
那么如何把x变成集合的根呢?只要把从x到根路径上的每一条边反向即可,所以不能进行路径压缩。
其实并查集的解法也有用 lct 的思想的。
在这里,并查集中的两点之间的边就表示连接两个洞穴之间的边,非常的直接。。
注意一个细节 : 题目中说——无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径
也就是说不会有环!这也正是能用并查集做的原因之一。
——代码
1 #include <cstdio> 2 #include <iostream> 3 #define N 10001 4 5 int n, m; 6 int f[N]; 7 8 inline int read() 9 { 10 int x = 0, f = 1; 11 char ch = getchar(); 12 for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1; 13 for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; 14 return x * f; 15 } 16 17 inline int find(int x) 18 { 19 while(x ^ f[x]) x = f[x]; 20 return x; 21 } 22 23 inline void make_root(int x, int c) 24 { 25 if(x ^ f[x]) make_root(f[x], x); 26 f[x] = c; 27 } 28 29 int main() 30 { 31 int i, j, x, y, fx, fy; 32 char s[10]; 33 n = read(); 34 m = read(); 35 for(i = 1; i <= n; i++) f[i] = i; 36 for(i = 1; i <= m; i++) 37 { 38 scanf("%s", s); 39 x = read(); 40 y = read(); 41 if(s[0] == 'Q') find(x) == find(y) ? puts("Yes") : puts("No"); 42 else if(s[0] == 'C') make_root(x, x), f[x] = y; 43 else make_root(x, x), f[y] = y; 44 } 45 return 0; 46 }