2020 MULTI-UNIVERSITY TRAINING CONTEST 2 Problem A (并查集)

题面

Problem Description
There are n cities and m bidirectional roads in Byteland. These cities are labeled by 1,2,…,n, the brightness of the i-th city is bi.

Magician Sunset wants to play a joke on Byteland by making a total eclipse such that the brightness of every city becomes zero. Sunset can do the following operations for arbitrary number of times:

· Select an integer k (1≤k≤n).

· Select k distinct cities c1,c2,…,ck (1≤ci≤n) such that they are connected with each other. In other words, for every pair of distinct selected cities ci and cj (1≤i<j≤k), if you are at city ci, you can reach city cj without visiting cities not in {c1,c2,…,ck}.

· For every selected city ci (1≤i≤k), decrease bci by 1.

Note that Sunset will always choose k with the maximum possible value. Now Sunset is wondering what is the minimum number of operations he needs to do, please write a program to help him.

Input
The first line of the input contains a single integer T (1≤T≤10), the number of test cases.

For each case, the first line of the input contains two integers n and m (1≤n≤100000, 1≤m≤200000), denoting the number of cities and the number of roads.

The second line of the input contains n integers b1,b2,…,bn (1≤bi≤109), denoting the brightness of each city.

Each of the following m lines contains two integers ui and vi (1≤ui,vi≤n,ui≠vi), denoting an bidirectional road between the ui-th city and the vi-th city. Note that there may be multiple roads between the same pair of cities.

Output
For each test case, output a single line containing an integer, the minimum number of operations.

Sample Input
1
3 2
3 2 3
1 2
2 3

Sample Output
4

思路

首先这应该是个并查集,这毫无疑问。我们每次一定是选择并查集里面的极大连通块然后操作这个集合里面最小权值次数,接着这个集合会分裂成多个联通快,我们继续操作就可以了。所以我们在实现的时候,首先我们在遍历边的时候,只会把比自身权值大的加入集合,然后我们最终应该先减去这个集合的最小值,然后加上集合之中非最小值的元素和最小值之间的差值,这样我们就得证了。

代码实现

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
typedef pair<int ,int> PII;
const int maxn=1e5+7;
int root[maxn],n,m;
ll weight[maxn];
vector <int > g[maxn];

int find (int x) {
    if (root[x]==x) return x;
    else return root[x]=find(root[x]);
}

inline void solve () {
    scanf ("%d %d",&n,&m);
    rep (i,1,n) scanf ("%lld",&weight[i]);
    vector <int > vec(n);
    rep (i,0,n-1) vec[i]=i+1;
    rep (i,1,n) {
        root[i]=i;
        g[i].clear ();
    }
    rep (i,1,m) {
        int u,v;
        scanf ("%d %d",&u,&v);
        g[u].pb (v);
        g[v].pb (u);
    }
    sort (vec.begin(),vec.end (),[](int a,int b){return weight[a]>weight[b]; });
    ll ans=0;
    for (int u:vec) 
     for (int v:g[u]) {
         if (weight[v]<weight[u]) continue;
         if (weight[u]==weight[v]) if (find(u)==find(v)) continue;
         ans+=weight[find(v)]-weight[u];
         root[find(v)]=u;
     }
    rep (i,1,n) if (find(i)==i) ans+=weight[i];
    cout<<ans<<endl;
}


int main () {
    int t;
    for (scanf ("%d",&t);t;t--) solve ();   
     return 0;
}   

猜你喜欢

转载自www.cnblogs.com/hhlya/p/13383060.html