题目链接
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.
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.
For each test case, output a single line containing an integer, the minimum number of operations.
1
3 2
3 2 3
1 2
2 3
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[i−1]−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);
}
}