1408E.Avoid Rainbow Cycles(最大生成树)

给定m套整数A1,A2,…,Am;这些集合的元素是1到n之间(包括1和n)的整数。

有两个正整数数组a1,a2,...,am和b1,b2,...,bn。

在一个操作中,您可以从集合Ai中删除元素j,并为此支付ai + bj硬币。

您可以执行几个(也许没有)操作(某些集合可能为空)。

在那之后,您将制作一个由n个顶点组成的边色无向图。对于每个集合Ai,您将为所有x,y∈Ai和x <y添加一条颜色为i的边(x,y)。某些顶点对可以连接多个边,但是这些边具有不同的颜色。

如果其上所有边的颜色都不同,则称为循环i1→e1→i2→e2→…→ik→ek→i1(ej是连接顶点ij和ij + 1的某些边)。

找出要获得没有彩虹周期的图表所需的最小硬币数量。

题解:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
typedef long long ll;
struct node {
    int u,v;
    ll w;
    bool operator < (const node &r) const {
        return w>r.w;
    }
}edge[maxn<<2];
int n,m;
ll a[maxn];
int father[maxn];
int findfather (int x) {
    int a=x;
    while (x!=father[x]) x=father[x];
    while (a!=father[a]) {
        int z=a;
        a=father[a];
        father[z]=x;
    }
    return x;
}
int main () {
    ll ans=0;
    int tot=0;
    scanf("%d%d",&m,&n);
    for (int i=1;i<=n+m;i++) scanf("%lld",a+i),father[i]=i;
    for (int i=1;i<=m;i++) {
        int k;
        scanf("%d",&k);
        for (int j=1;j<=k;j++) {
            int x;
            scanf("%d",&x);
            ll v=a[i]+a[m+x];ans+=v;
            edge[++tot]={i,m+x,v};
        }
    }
    sort(edge+1,edge+tot+1);
    for (int i=1;i<=tot;i++) {
        int x=edge[i].u;
        int y=edge[i].v;
        x=findfather(x);
        y=findfather(y);
        if (x==y) continue;
        ans-=edge[i].w;
        father[y]=x;
    }
    printf("%lld
",ans);
}
原文地址:https://www.cnblogs.com/zhanglichen/p/14352629.html