并查集的高效之处在于路径压缩和延迟更新。
在本题中需要额外维护子树的规模以及当前子树节点到跟的距离两个数组。
由于一个新的数必然是两棵树拼接而成,对于子树规模的更新直接相加即可,
对于节点到跟的距离:
我们让a树的根指向b树的根,同时更新a树根到(a+b)树根(即b树根)的距离为size_of(Tree(b))即可完成维护。
http://poj.org/problem?id=1988
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int maxn = 1e5 + 10; 6 int m, a, b; 7 int fa[maxn], d[maxn], size[maxn]; 8 char ch; 9 10 int father(int u){ 11 //path compressing 12 if(fa[u] == u) return u; 13 int t = fa[u]; 14 fa[u] = father(fa[u]); 15 d[u] += d[t]; 16 return fa[u]; 17 } 18 19 void solve(){ 20 if(ch == 'M'){ 21 int ra = father(a); 22 int rb = father(b); 23 fa[ra] = rb; 24 d[ra] += size[rb]; 25 size[rb] += size[ra]; 26 return; 27 } 28 int ra = father(a); 29 printf("%d ", d[a]); 30 } 31 32 int main(){ 33 #ifndef ONLINE_JUDGE 34 freopen("in.txt", "r", stdin); 35 #endif 36 while(~scanf("%d", &m)){ 37 for(int i = 0; i <= m; i++) fa[i] = i, d[i] = 0, size[i] = 1; 38 for(int i = 0; i < m; i++){ 39 scanf(" %c%d", &ch, &a); 40 if(ch == 'M') scanf("%d", &b); 41 solve(); 42 } 43 } 44 return 0; 45 }