HDUOJ 6763 Total Eclipse

HDUOJ 6763 Total Eclipse

题目链接

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

· 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≤1e9), 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

思维+并查集~
题意就是每次选一个连通块,连通块的每个点的 b r i g h t n e s s > 0 brightness>0 brightness>0,然后将每个点的的 b r i g h t n e s s brightness brightness 减一,问最少的操作次数使得所有点的 b r i g h t n e s s = 0 brightness=0 brightness=0
由连通块很容易想到并查集,我们可以将所有点按 b r i g h t n e s s brightness brightness 从大到小排列,模拟由大变小的一个过程,用 n u m num num 记录连通块的数量,那么对每个点 i i i,需要的最少操作次数即为 n u m ∗ ( b [ i − 1 ] − b [ i ] ) num*(b[i-1]-b[i]) num(b[i1]b[i]),关键点就放在了找连通块数量上,怎么进行并查集的操作呢:
可以设一个标记 v i s vis vis 判断点有没有遍历到,对每个点,遍历与之相连的点,若未访问就直接跳过,若访问了判断父亲结点是否相同,不同则进行合并操作,此时连通块的数量减一,每次累加答案即可,AC代码如下:

#include
using namespace std;
typedef long long ll;
const int N=1e5+5;
int t,n,m,u,v,father[N],vis[N];
vector<int>g[N];
struct node{
    int id,b;
}p[N];
int Findfather(int x){
    return father[x]==x?x:father[x]=Findfather(father[x]);
}

bool cmp(node a,node b){
    return a.b>b.b;
}

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&p[i].b);
            p[i].id=i;
            father[i]=i;
            vis[i]=0;
            g[i].clear();
        }
        sort(p+1,p+1+n,cmp);
        while(m--){
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        ll num=1,ans=0;
        vis[p[1].id]=1;
        for(int i=2;i<=n;i++){
            ans+=num*(p[i-1].b-p[i].b);
            num++;
            for(auto j:g[p[i].id]){
                int u=j,v=p[i].id;
                if(!vis[u]) continue;
                u=Findfather(u),v=Findfather(v);
                if(u!=v){
                    father[u]=v;
                    num--;
                }
            }
            vis[p[i].id]=1;
        }
        ans+=num*p[n].b;
        printf("%lld\n",ans);
    }
}

你可能感兴趣的:(并查集,HDUOJ)