B - Almost Union-Find
本题考点:并查集中元素的删除的实现方法
题目链接
————————————————————————————————————————
题意:
给你n个数,刚开始每个数都是独立的个体;接下来有m行操作,有三种指令:
1:让a和b两个图连通。
2:把a从原来的图中拿出来并放进b图中。
3:输出p所在图中元素个数和元素和。
思路:
并查集了,只不过该题要考虑到并查集中元素的删除,通过了解,知道元素的删除就是在最后面在建立一个元素并把要删除的元素指向最后面新建立的元素,并把原来位置上的所有“痕迹”全部清除,这样该元素就如“改过自新”般的变成了一个新元素。
f[]记录元素在哪一个位置,id[]记录元素的编号,sum[]记录所在集合内元素的个数,s[]记录所在集合内元素的和。
————————————————————————————————————————
代码:
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#define inf 99999999
using namespace std;
int n,m;
int sum[200010],s[200010];//sum元素个数,s元素和
int id[200010];
int f[200010];
int getf(int v)//找BOSS
{
int x;
x=v;
while(x!=id[x])
x=id[x];
return x;
}
void merge(int a,int b)
{
int t1,t2;
t1=getf(a);
t2=getf(b);
if(t1!=t2)
{
id[t1]=t2;
sum[t2]+=sum[t1];
s[t2]+=s[t1];
}
}
int main()
{
int i,j,k;
int x,p,q;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
{
f[i]=i;
sum[i]=1;
s[i]=i;
id[i]=i;
}
k=n;
while(m--)
{
scanf("%d",&x);
if(x==1)
{
scanf("%d%d",&p,&q);
merge(f[p],f[q]);
}
else if(x==2)
{
scanf("%d%d",&p,&q);
if(p!=q)
{
int t=getf(f[p]);//把p从原来的图里面踢出去
sum[t]--;
s[t]-=p;
k++;
f[p]=k;//再让p成为独立的个体
id[f[p]]=f[p];
sum[f[p]]=1;
s[f[p]]=p;
merge(f[p],f[q]);
}
}
else if(x==3)
{
scanf("%d",&p);
int r=getf(f[p]);//直接输出
printf("%d %d\n",sum[r],s[r]);
}
}
}
return 0;
}