0
点赞
收藏
分享

微信扫一扫

Almost Union-Find UVA - 11987


2操作为关键

当一个元素从一个集合被并入另一个集合时,以该元素为根的所有节点会一同被并入另一集合

 

因此该操作通过建立 虚点 实现

所谓虚点,即其所在集合的数量与节点总和均不考虑该点

要将x节点并入y节点所在集合 首先将x从原集合删除 新建一个虚点并将x归入以该虚点为祖先的集合 然后再将以虚点为祖先的集合与以y所在集合进行合并

具体实现为 在f[n]数组中新开辟一个元素,再通过real[n]数组记录x节点的虚点(新祖先)

假设z为以x为根的节点 当需要查找z元素的祖先时,通过getf()函数依然可以找到其祖先,因为此时real[z]=z,即该点并未进行过2操作

#include <bits/stdc++.h>
using namespace std;

int f[100010],realf[100010],num[100010],sum[100010];
int n,q;

int getf(int p)
{
if(f[p]==p) return p;
else
{
f[p]=getf(f[p]);
return f[p];
}
}

void uniteI(int x,int y)
{
int fx,fy;
fx=getf(realf[x]);
fy=getf(realf[y]);
if(fx!=fy)
{
num[fx]+=num[fy];
sum[fx]+=sum[fy];
num[fy]=0;
sum[fy]=0;
f[fy]=fx;
}
return;
}

void uniteII(int x,int y)
{
int fx,fy;
fx=getf(realf[x]);
fy=getf(realf[y]);
if(fx!=fy)
{
num[fx]--;
sum[fx]-=x;
num[fy]++;
sum[fy]+=x;
realf[x]=fy;
}
return;
}

int main()
{
int i,o,x,y,fx,fy;
while(scanf("%d%d",&n,&q)!=EOF)
{
for(i=1;i<=n;i++)
{
f[i]=i;
realf[i]=i;
num[i]=1;
sum[i]=i;
}
while(q--)
{
scanf("%d",&o);
if(o==1)
{
scanf("%d%d",&x,&y);
uniteI(x,y);
}
if(o==2)
{
scanf("%d%d",&x,&y);
uniteII(x,y);
}
if(o==3)
{
scanf("%d",&x);
fx=getf(realf[x]);
printf("%d %d\n",num[fx],sum[fx]);
}
}
}
return 0;
}

 

 


举报

相关推荐

0 条评论