您的位置:首页 > 其它

UVA11987 并查集

2016-10-05 00:27 246 查看
第一、三个操作 直接带权并查集就可以解决关键是第二个

第二个问题在于合并两个节点的时候 第一个节点的子节点会跟着合并到第二个节点中  这提示我们 只要1~n都不作为父节点就可以了

所以初始化的时候将 每个节点的父亲节点设为 n+i 这样无论怎样合并节点1~n都不可能成为父节点  那么进行第二个操作的时候只要 将p节点合并到q节点父节点下就可以了

具体看代码 第一个操作和第二个操作合并时的区别

网上还有一种方法就是删边 滞空节点 建新节点  感觉没有这个方法简单好理解。

#include <iostream>
#include<cstdio>
#include<cstring>

using namespace std;
typedef long long ll;
const int maxn=200010;
int pa[maxn],cnt[maxn];
ll sum[maxn];
int n,m;
void init()
{
for(int i = 1; i <= n; ++i) {
pa[i]=i+n;
cnt[i+n]=1;
sum[i+n]=i;
}
for(int i = 1; i <=n; ++i) {
pa[i+n]=i+n;
}
}
int findset(int x)
{
return x==pa[x]?x:pa[x]=findset(pa[x]);
}
int main()
{
// freopen("in.txt","r",stdin);
int t,p,q;
while(~scanf("%d%d",&n,&m)) {
init();
while(m--) {
scanf("%d",&t);
if(t==1) {
scanf("%d%d",&p,&q);
int x=findset(p),y=findset(q);
if(x!=y) {
pa[x]=y;
cnt[y]+=cnt[x];
sum[y]+=sum[x];
}
}
else if(t==2) {
scanf("%d%d",&p,&q);
int x=findset(p),y=findset(q);
if(x!=y) {
pa[p]=y;
cnt[x]--;
cnt[y]++;
sum[y]+=p;
sum[x]-=p;
}
}
else {
scanf("%d",&p);
int x=findset(p);
printf("%d %d\n",cnt[x],sum[x]);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: