您的位置:首页 > 其它

UVA 11987 Almost Union-Find(并查集的删除)

2016-11-23 01:22 441 查看
题目大意:
初始时,一共有n个元素的组合1,2,3....n
给出三个操作
1 p q:合并p,q所在的集合
2 p q:把p移动到q所在的集合
3 p:输出p所在的集合的元素的个数还有元素之和
题目分析:
    第一和第三个都比较简单,就是普通的并查集问题,刚看题目的时候以为都比较简单,后来做的时候,才发现第二个操作是一个比较复杂的删除问题,就是把p从原来的集合中移除,再加入到q所在的集合中去。这样就比较麻烦了,因为这个只有子节点指向父亲结点,所以如果p结点是叶子结点的话,可以直接删除,如果是其他结点的父节点的话,就不能直接删除了。后来的办法是再建一个id数组,用来记录结点,然后如果要删除的话,sum和cnt两个数组直接减去,就可以看做是已经删除的了。其实,如果没有第二步操作的话,id数组是可以直接不需要的,但是有第二步操作,所以id数组值就代表当前这个结点的存储信息的位置。理解好id数组是关键。
#include <cstdio>
#include <cstring>
#include <map>
#include <queue>
using namespace std;
const  int maxn = 100001;
int pa[maxn],cnt[maxn],id[maxn],tot;
int sum[maxn];
int find(int x){
if(x == pa[x])
return x;
else return pa[x] = find(pa[x]);
}
void unit(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx != fy){
pa[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;
pa[tot]=tot;
cnt[tot]=1;
sum[tot]=x;
}
int main(){
int t,k,n,m,u,v;
while(~(scanf("%d%d",&n,&m))){
tot=n;
for(int i=0;i<=n;i++){
sum[i]=pa[i]=id[i]=i;
cnt[i]=1;
}
while(m--){
scanf("%d",&k);
if(k == 1){
scanf("%d%d",&u,&v);
unit (id[u],id[v]);
}
if(k == 2){
scanf("%d%d",&u,&v);
int fx = find(id[u]);
int fy = find(id[v]);
if(fx != fy){
del(u);
unit (id[u],id[v]);
}
}
if(k == 3){
scanf("%d",&u);
printf("%d %ld\n",cnt[find(id[u])],sum[find(id[u])]);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: