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

题目链接 https://cn.vjudge.net/problem/UVA-11987

【题意】
题意:初始有N个集合,分别为 1 ,2 ,3 …..n。有三种操件
1 p q 合并元素p和q的集合
2 p q 把p元素移到q集合中
3 p 输出p元素集合的个数及所有元素和

【思路】
并查集维护两个值一个是集合中元素个数,一个是总和,那么最难处理的就是操作2,把p元素移动到q元素所在集合中,相当于把p元素从所在集合中删掉. 而并查集没有删除操作,所以这里用了一个等价的做法是把p对应的根结点的信息更新(个数减一,和减去p),然后在申请一个新节点id[p]来表示p元素

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

const int maxn=100005<<1;

int n,m;
int par[maxn],id[maxn],pos;
int cnt[maxn];
ll sum[maxn];

void init(){
    for(int i=1;i<maxn;++i){
        par[i]=i;
        sum[i]=(ll)i;
        cnt[i]=1;
        id[i]=i;
    }
    pos=n+1;
}

int find(int x){
    return par[x]==x?x:par[x]=find(par[x]);
}

int main(){
    while(scanf("%d%d",&n,&m)==2){
        init();
        while(m--){
            int tp;
            scanf("%d",&tp);
            if(tp==1){
                int x,y;
                scanf("%d%d",&x,&y);
                int r1=find(id[x]);
                int r2=find(id[y]);
                if(r1!=r2){
                    par[r1]=r2;
                    sum[r2]+=sum[r1];
                    cnt[r2]+=cnt[r1];
                }
            }
            else if(tp==2){
                int x,y;
                scanf("%d%d",&x,&y);
                int r1=find(id[x]);
                int r2=find(id[y]);
                if(r1!=r2){
                    sum[r1]-=(ll)x;
                    --cnt[r1];
                    id[x]=pos++;
                    sum[id[x]]=(ll)x;
                    cnt[id[x]]=1;
                    par[id[x]]=r2;
                    sum[r2]+=sum[id[x]];
                    cnt[r2]+=cnt[id[x]];
                }
            }
            else{
                int x;
                scanf("%d",&x);
                int rt=find(id[x]);
                printf("%d %lld\n",cnt[rt],sum[rt]);
            }
        }
    }
    return 0;
}
posted @ 2018-08-18 22:34  不想吃WA的咸鱼  阅读(114)  评论(0编辑  收藏  举报