加权并查集详解

加权并查集,就是普通的并查集加了个权值。以题目来举例吧。

HDU 3038  点击打开链接

题意:给你m个区间的区间端点及区间和,一个个的读入这些区间,问有多少个区间与前面的区间冲突。

分析:将区间端点看成是一个节点,用一个parent[i]数组表示结点i指向的父节点,用一个sum[i]数组表示结点i到父节点的权值。运用了前缀和的思想。

代码:

#include<iostream>
#include<cstring>
using namespace std;
const int N = 2e5+5;
int n,m,s[N],p[N],ans;

void init(){
    ans=0;
    memset(s,0,sizeof(s));
    for(int i=0;i<N;i++)
        p[i]=i;
}

int fd(int x) { ///此时find不单有查找任务,还有更新距离任务
    if(x==p[x]) return x;
    int t=p[x];
    p[x]=fd(p[x]);
    s[x]+=s[t]; ///记录到根节点的距离,一定要有一个思想,根节点是一个区间的一个端点而不是一个区间,输入的区间被合并成了两个点
    return p[x];
}

void Union(int a,int b,int num) {
    int x=fd(a),y=fd(b);
    if(x==y) {
        if(s[b]!=s[a]+num) ans++;
    }else {
        p[y]=x;
        s[y]=s[a]+num-s[b]; ///y到x的距离等于a到x的距离+b到a的距离-b到y的距离
    }
}

int main(){
    while(cin>>n>>m) {
        init();
        for(int i=0;i<m;i++) {
            int a,b,c;
            cin>>a>>b>>c;
            Union(a-1,b,c);
            ///等价于Union(a,b+1,c);
        }
        cout<<ans<<endl;
    }
}


牛客网  第十四届华中科技大学程序设计竞赛决赛同步赛 A - Beauty of Trees  点击打开链接

题意:给你m个区间的区间端点及区间亦或和,一个个的读入这些区间,问有多少个区间与前面的区间冲突。

分析:此题与上一题差不多,只不过将区间和改成了区间亦或和,原理都是一样的,利用亦或的性质维护一个前缀亦或和。

代码:

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5+10;
int n,m,s[N],p[N],k,f;

void init(){
    f=0;
    for(int i=0;i<N;i++) p[i]=i;
    memset(s,0,sizeof(s));
}

int fd(int x) {
    if(x==p[x]) return x;
    int t=p[x];
    p[x]=fd(p[x]);
    s[x]^=s[t];
    return p[x];
}

void Union(int a,int b,int c) {
    int x=fd(a),y=fd(b);
    if(x==y) {
        if(s[b]!=(s[a]^c)) cout<<k<<endl,f=1; ///亦或这里一定要打括号,亦或的优先级低于!=
    }else {
        p[y]=x;
        s[y]=s[a]^s[b]^c;
    }
}

int main(){
    while(cin>>n>>m) {
        init();
        for(k=1;k<=m;k++) {
            int a,b,c;
            cin>>a>>b>>c;
            Union(a-1,b,c);
        }
        if(!f) cout<<-1<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/tianwei0822/article/details/80267471