I hope you know the beautiful Union-Find structure. In this problem, you're to implement something similar, but not identical.
The data structure you need to write is also a collection of disjoint sets, supporting 3 operations:
1 p q
Union the sets containing p and q. If p and q are already in the same set, ignore this command.
2 p q
Move p to the set containing q. If p and q are already in the same set, ignore this command
3 p
Return the number of elements and the sum of elements in the set containing p.
Initially, the collection contains n sets: {1}, {2}, {3}, ..., {n}.
Input
There are several test cases. Each test case begins with a line containing two integers n and m (1<=n,m<=100,000), the number of integers, and the number of commands. Each of the next m lines contains a command. For every operation, 1<=p,q<=n. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
Output
For each type-3 command, output 2 integers: the number of elements and the sum of elements.
Sample Input
5 7 1 1 2 2 3 4 1 3 5 3 4 2 4 1 3 4 3 3
Output for the Sample Input
3 12 3 7 2 8
题意:可删点的并查集。
1 p q 合并元素P和Q所在的集合,如果二者已经在同一个集合中,忽略此命令
2 p q 把元素P移动到Q所在的集合。如果二者已经在同一个集合中,忽略此命令
3 p 输出p所在集合的元素个数
思路:点不要真删,只是将那个点的祖先的size-1,sum-这个点。然后开个新点。用个数组pos[]表示这个点现在的位置。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 200080 #define LL long long int int pos[maxn],father[maxn],rank1[maxn]; LL sum[maxn]; int cnt; int find(int x) { if(x == father[x]) return x; return father[x] = find(father[x]); } void init(int n) { for(int i = 1;i <= n;i++) { father[i] = i; rank1[i] = 1; pos[i] = i; sum[i] = i; } } void Union(int a,int b) { int fa = find(a),fb = find(b); if(fa == fb) return; father[fa] = fb; rank1[fb] += rank1[fa]; sum[fb] += sum[fa]; } void Delete(int x) { int xx = pos[x]; int fx = find(xx); rank1[fx]--; sum[fx] -= x; pos[x] = ++cnt; father[cnt] = cnt; rank1[cnt] = 1; sum[cnt] = x; } void Update_Union(int a,int b) { int posa = pos[a],posb = pos[b]; Union(posa,posb); } void Update_Move(int a,int b) { int posa = pos[a],posb = pos[b]; if(find(posa) == find(posb)) return; Delete(a); Union(pos[a],posb); } int query(int x) { int posx = pos[x]; int fx = find(posx); return fx; } int main() { //freopen("in.txt","r",stdin); int n,m,ope,p,q; while(scanf("%d%d",&n,&m)==2) { init(n); cnt = n; while(m--) { scanf("%d",&ope); switch(ope) { case(1):{scanf("%d%d",&p,&q); Update_Union(p,q); break;} case(2):{scanf("%d%d",&p,&q); Update_Move(p,q); break;} case(3):{scanf("%d",&p); int pos = query(p); printf("%d %lld\n",rank1[pos],sum[pos]); break;} } } } return 0; }