题意:
初始时,一共有n个元素的组合1,2,3....n
给出三个操作
1 p q:合并p,q所在的集合
2 p q:把p移动到q所在的集合
3 p:输出p所在的集合的元素的个数
思路:
比较巧妙的并查集,我们通过编号来标记节点,当一个元素移除的时候,我们可以通过对其目前父节点的sum与cnt进行更新,只要减掉就可以看做已经移除了
而目前这个数值对应的值可以改成一个还没有使用的地址来标记,然后再合并地址
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <list>
#include <algorithm>
#include <climits>
using namespace std;
#define lson 2*i
#define rson 2*i+1
#define LS l,mid,lson
#define RS mid+1,r,rson
#define UP(i,x,y) for(i=x;i<=y;i++)
#define DOWN(i,x,y) for(i=x;i>=y;i--)
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define LL long long
#define N 200005
#define INF 0x3f3f3f3f
#define EXP 1e-8
#define lowbit(x) (x&-x)
const int mod = 1e9+7;
int father[N],cnt[N],sum[N],id[N];
int n,m,tot;
int find(int x)
{
if(x==father[x]) return x;
return father[x] = find(father[x]);
}
void Union(int x,int y)
{
int fx = find(x);
int fy = find(y);
if(fx!=fy)
{
father[fx] = fy;
sum[fy]+=sum[fx];
cnt[fy]+=cnt[fx];
}
}
void del(int x)
{
int fx = find(id[x]);
sum[fx]-=x;
cnt[fx]--;
tot++;
id[x] = tot;
father[tot] = tot;
cnt[tot] = 1;
sum[tot] = x;
}
int main()
{
int i,j,k,op,x,y;
while(~scanf("%d%d",&n,&m))
{
tot = n;
for(i = 0; i<=n; i++)
{
father[i] = sum[i] = id[i] = i;
cnt[i] = 1;
}
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
Union(id[x],id[y]);
}
else if(op==2)
{
scanf("%d%d",&x,&y);
int fx = find(id[x]);
int fy = find(id[y]);
if(fx!=fy)
{
del(x);
Union(id[x],id[y]);
}
}
else
{
scanf("%d",&x);
int fx = find(id[x]);
printf("%d %d\n",cnt[fx],sum[fx]);
}
}
}
return 0;
}