杭电多校round2 1001 Total Eclipse(并查集)

问题描述

拜特兰有n个城市和m条双向道路。这些城市被标记为1,2,…,n,第i个城市的亮度是bi。
魔术师Sunset想和拜特兰开个玩笑,制造一个月全食,使每个城市的亮度变为零。Sunset可以执行以下操作任意次数:
·选择一个整数k(1≤k≤n)。
·选择k个不同的城市c1,c2,…,ck(1≤ci≤n),使它们相互连接。换言之,对于每一对不同选择的城市ci和cj(1≤i<j≤k),如果您在city ci,您可以到达city cj,而不必访问{c1,c2,…,ck}以外的城市。
·对于每个选定的城市ci(1≤i≤k),将bci降低1。
请注意,Sunset将始终选择具有最大可能值的k。现在Sunset想知道他需要做的最小操作数是多少,请编写一个程序来帮助他。
输入
输入的第一行包含单个整数T(1≤T≤10),即测试用例的数量。
对于每种情况,输入的第一行包含两个整数n和m(1≤n≤100000,1≤m≤200000),表示城市数量和道路数量。
输入的第二行包含n个整数b1,b2,…,bn(1≤bi≤109),表示每个城市的亮度。
以下每一条m线包含两个整数ui和vi(1≤ui,vi≤n,ui≠vi),表示第ui个城市和第vi个城市之间的一条双向道路。请注意,同一对城市之间可能有多条道路。

输出

对于每个测试用例,输出一行包含一个整数,即最小操作数。

样本输入

1
3 2
3 2 3
1 2
2 3

样本输出

4

1001清题思路:

并查集,把点从大到小排,大的先进入图中,对于遍历每个点x与之相连的已在图中的点y(因为大的先入图,b[y]>b[x]),要使点y的亮度与x相等需要(b【y】-b【x】)个的操作,之后的x和y的亮度相等且相连,可以同时操作。可以将其合并为一个点(合并祖宗)。以此往复,最后剩下几个独立没法合并的点(几个祖宗),值加上就行。

样例如图变化:

一开始1号点进入图,与之相连的点(2号)没有一个在图中,跳过。

在这里插入图片描述

之后3号点进入图,同样与之相连的点没一个在图中,跳过。
在这里插入图片描述

最后2号点进入,1号与之相连,sum加上两者的差值,把1号的祖先标为2.
相当于1号进行-1亮度操作.sum+=1
在这里插入图片描述

3号与2号相连,sum加上两者之差,把3的祖先标为2.相当于3号进行-1亮度操作.sum+=1
在这里插入图片描述

最后sum加上祖先(2的祖先还是标为2,所以2是祖先)的值。相当于2号和它的孩子(1,3)同时进行-2亮度操作。sum+=2
在这里插入图片描述

最后
sum=4
代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10,M=4e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int t,n,m;
int b[N],f[N],vis[N];
struct node{
 int id;
 int b;
}a[N];
vector<int>q[N];
int cmp(node x,node y){
 return x.b>y.b;
}
int find(int x){
 if(x==f[x])return f[x];
 else return f[x]=find(f[x]);
}
int main() {
scanf("%d",&t);
while(t--){
 memset(vis,0,sizeof(vis));
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++){
   scanf("%d",&b[i]);
   f[i]=i;
   a[i].b=b[i];
   a[i].id=i;
  }
  sort(a+1,a+1+n,cmp);
for(int i=1;i<=m;i++){
 int x,y;
 scanf("%d%d",&x,&y);
 q[x].push_back(y);
 q[y].push_back(x);
}
ll sum=0;
for(int i=1;i<=n;i++){
 int k=a[i].id;
// cout<<k<<endl;
 vis[k]=1;
 for(int j=0;j<q[k].size();j++){
  if(vis[q[k][j]]==0)continue;
  int x=find(k),y=find(q[k][j]);
 // printf("%d %d\n",k,q[k][j]);
  if(x!=y){
   sum+=b[y]-b[k];
   f[y]=k;  
  }
 }
}
for(int i=1;i<=n;i++){
 if(f[i]==i)
 sum+=b[i];
}
printf("%lld\n",sum);
for(int i=1;i<=n;i++)q[i].clear();
} 
}

猜你喜欢

转载自blog.csdn.net/Nefeertari/article/details/107559406