标签:判断 wap its math ons php bool nod ret
链接
给你一张n个点m条边的无向图,有点权,每次选一个连通块,你可以将块内所有点的点权减一,当某个点点权减到零时就消失,问最少进行多少次操作可以使整张图消失。
\((1<=n<=10^5,1<=m<=2*10^5,T<=10,可能有重边)\)
假设没有边,所有点都需要减点权遍才能减完,每加上来一条边,就会有一对点公用一些操作,公用操作的数量应该是本边点权较小的那个点权,然而有可能一端的点权已经跟另一端所连的点公用了一些了,此时,要么不能就不能公用那么多,要么早都公用完了。
因此,加入一条边需要判断边两边的点是否在同一个连通块中,如果不在,那么这两个连通块一定能公用 较小点权 个操作;如果在一个连通块就比较麻烦,公用操作 比 较小点权 小,那就要减小差值,不过,如果我们将边按照较小点权降序排序就不存在这种情况了!
加边判断连通性,并查集,就很显然了。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=100005;
int f[N],n,m;
LL ans,b[N];
struct node
{
int qi,zhong;
node(int _qi=0,int _zhong=0)
{
qi=_qi;
zhong=_zhong;
}
}bian[N<<2];
int find(int x)
{
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
void unin(int x,int y)
{
int xx=find(x);
int yy=find(y);
f[xx]=yy;
}
bool judge(int x,int y)
{
int xx=find(x);
int yy=find(y);
return xx==yy;
}
bool com(node x,node y)
{
if(b[x.zhong]==b[y.zhong])return b[x.qi]>b[y.qi];
else return b[x.zhong]>b[y.zhong];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
ans=0;
for(int i=1;i<=n;i++)scanf("%lld",&b[i]),ans+=b[i];
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&bian[i].qi,&bian[i].zhong);
if(b[bian[i].qi]<b[bian[i].zhong])swap(bian[i].qi,bian[i].zhong);
}
sort(bian+1,bian+1+m,com);
for(int i=1;i<=m;i++)
{
if(judge(bian[i].qi,bian[i].zhong))continue;
unin(bian[i].zhong,bian[i].qi);
ans-=min(b[bian[i].zhong],b[bian[i].qi]);
}
printf("%lld\n",ans);
}
}
标签:判断 wap its math ons php bool nod ret
原文地址:https://www.cnblogs.com/LiqgNonqfu/p/13568434.html