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

来源:互联网 发布:大数据培训骗局 编辑:程序博客网 时间:2024/06/05 16:13
题目大意:

初始时,一共有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;}

0 0