• 带权并查集


    例题一链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=3038

    题意:

    给出一些区间和,如果某个区间和与前面的区间和产生矛盾,那么就忽略它

    计算错误的区间和的数量

    分析: 

     将每个前缀和看作是一个节点,建立并查集,每个节点不但保存父节点,还保存它与父节点的差值

    对于同一个并查集中的节点,他们的差值是确定的,这个时候错误的区间和就能立马发现

    不同并查集的节点,他们差值不确定,这个时候可以根据区间和来合并两个并查集

    AC代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define pii pair<int,int>
    using namespace std;
    const int maxn=2e5+7;
    const int mod=1e9+7;
    ll offe[maxn],boss[maxn];
    int fin(int x){
        if(x==boss[x])return x;
        int z=boss[x];
        int y=fin(boss[x]);
        offe[x]+=offe[z];
        boss[x]=y;
        return y;
    }
    int main()
    {
        int n,m,ans=0;
        while(scanf("%d %d",&n,&m)==2){
            ans=0;
            for(int i=0;i<=n;i++)boss[i]=i,offe[i]=0;
            for(int i=1;i<=m;i++){
                int l,r,x;
                scanf("%d %d %d",&l,&r,&x);
                l--;
                if(fin(l)==fin(r)){
                    if(offe[l]-offe[r]!=x)ans++;
                }else{
                    int fl=fin(l),fr=fin(r);
                    boss[fl]=fr;
                    offe[fl]=x-offe[l]+offe[r];
                }
            }
            printf("%d
    ",ans);
        }
    	return 0;
    }
    

     

     

    例题二链接:

    https://codeforces.com/problemset/problem/1290/C

    题意:

     给出一排灯泡的状态,和一些操作集合,每个集合包括一些灯泡,代表改变这些灯泡的状态

     每个灯泡最多保存在两个集合中,求使得每个前缀灯泡都点亮的最少操作数

    分析: 

     为操作建立两个节点,一个是使用这个操作需要的花费,一个是不使用这个操作的花费

     有两种情况,如果某个灯只能被一个集合包含,那么这个操作集合一定执行或者不执行

     如果这个灯被两个集合包含,如果灯亮的,那么两个集合都激活,或者都不激活,如果灯灭的,那么只能有一个集合激活

     利用这些关系,将他们连接起来,取最优解,具体看代码

     

     参考:https://www.cnblogs.com/uid001/p/12272628.html

    AC代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=3e5+7;
    vector<int>ve[maxn];
    int boss[maxn*2],sz[maxn*2],n,k;
    char S[maxn];
    int fin(int x){
        if(x==boss[x])return x;
        return boss[x]=fin(boss[x]);
    }
    void unio(int x,int y){
        x=fin(x),y=fin(y);
        if(x!=y){
            boss[x]=y;
            sz[y]+=sz[x];
        }
    }
    int cal(int x){
        return min(sz[fin(x)],sz[fin(x+k)]);
    }
    int main(){
        scanf("%d %d",&n,&k);
        scanf("%s",S+1);
        for(int i=1;i<=2*k+1;i++)boss[i]=i;
        for(int i=k+1;i<=2*k;i++)sz[i]=1;
        sz[2*k+1]=1e9;
        for(int i=1;i<=k;i++){
            int num,x;
            scanf("%d",&num);
            while(num--){
                scanf("%d",&x);
                ve[x].push_back(i);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++){
             if(ve[i].size()==1){
                  ans-=cal(ve[i][0]);
                  if(S[i]=='1')unio(ve[i][0]+k,2*k+1);
                  else unio(ve[i][0],2*k+1);
                  ans+=cal(ve[i][0]);
             }else if(ve[i].size()==2){
                int a=ve[i][0],b=ve[i][1];
                if(fin(a)!=fin(b)&&fin(a)!=fin(b+k)){
                    ans-=(cal(a)+cal(b));
                    if(S[i]=='1')unio(a,b),unio(a+k,b+k);
                    else unio(a,b+k),unio(a+k,b);
                    ans+=cal(a);
                }
             }
             printf("%d
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    softice 在winice中的安装 zt
    普通版和优秀版简历的20项对比
    今天又投了几家。。等啊。。。
    乱写
    反攻击技术综合分析报告
    今天投简历的公司
    #pragma 预处理指令详解
    黑客入侵无线网络常用手段
    ADODB.Stream漏洞
    利用TCP/IP的堆栈指纹的方法
  • 原文地址:https://www.cnblogs.com/carcar/p/12290373.html
Copyright © 2020-2023  润新知