11987 - Almost Union-Find(并查集删除操作)

该题的难点就在于删除操作,  对于删除操作是有一个通用方法的 。     首先我们要明确,由于并查集是一个树状结构,内部关系复杂,所以如果将其中的一个点直接拆出来,势必会导致树状结构解体。   那么怎么办呢? 我们其实可以不必改变其原有结构,而是用一个id[i]数组表示元素i的编号,每次的删除操作即给元素i分配一个新的编号。因为要求输出集合的元素个数和他们的和,所以我们需要维护这个信息,因为并查集的根结点在路径压缩中是不变的,所以将这两个信息维护在根结点上就行了。

细节参见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;
const int maxm = 200000 + 5;
const int INF = 1000000000;
int T,n,a,x,y,m,cnt[maxm],sum[maxm],p[maxm],id[maxn],kase;
void init(int v) {
    for(int i=1;i<=v;i++) {
        p[i] = i;
        sum[i] = i;
        cnt[i] = 1;
        id[i] = i;
    }
}
int findset(int x) { return p[x] == x ? x : p[x] = findset(p[x]); }
int main() {
    while(~scanf("%d%d",&n,&m)) {
        init(n);
        kase = n + 1;
        while(m--) {
            scanf("%d",&a);
            if(a == 1) {
                scanf("%d%d",&x,&y);
                int xx = id[x], yy = id[y] ;
                xx = findset(xx); yy = findset(yy);
                if(xx != yy) {
                    p[xx] = yy;
                    cnt[yy] += cnt[xx];
                    sum[yy] += sum[xx];
                }
            }
            else if(a == 2) {
                scanf("%d%d",&x,&y);
                int xx = id[x], yy = id[y];
                xx = findset(xx); yy = findset(yy);
                if(xx != yy) {
                    sum[xx] -= x; cnt[xx]--;
                    id[x] = kase++;
                    xx = id[x];
                    p[xx] = yy;
                    cnt[yy] += 1; sum[yy] += x;
                }
            }
            else {
                scanf("%d",&x);
                x = id[x];
                x = findset(x);
                printf("%d %d\n",cnt[x],sum[x]);
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值