【杭电多校2020】第二场1001.Total Eclipse(并查集)

题目链接

思路:

按照权值从大到小排序,然后依次加入,并把全场的权值都减到当前权值。用并查集维护连通块的总个数即可。

代码:

#include
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e5+7;
const int M=4e5+8;
const double eps=1e-8;
const int mod=1e9+7;
const int inf=0x7fffffff;
const double pi=3.1415926;
int a[N],h[N],e[M],ne[M],f[N],q[N],fa[N],idx;
bool visit[N];
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
int find(int x)
{
	if(x!=f[x])
	{
		f[x]=find(f[x]);
	}
	return f[x];
}
int cmp(int x,int y)
{
	return a[x]>a[y];
}
signed main()
{
	IOS;
	int t;
	cin>>t;
	while(t--)
	{
		memset(h,-1,sizeof h);
		memset(visit,0,sizeof visit);
		memset(fa,0,sizeof fa);
		int n,m;
		cin>>n>>m;
		idx=0;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			f[i]=q[i]=i;
		}
		for(int i=1;i<=m;i++)
		{
			int x,y;
			cin>>x>>y;
			add(x,y);
			add(y,x);
		}
		sort(q+1,q+1+n,cmp);
		for(int i=1;i<=n;i++)
		{
			int u=q[i];
			visit[u]=1;
			for(int j=h[u];~j;j=ne[j])
			{
				int k=e[j];
				if(!visit[k])
				{
				    continue;
				}
				int v=find(k);
				if(v==u)
				{
				    continue;
				}
				f[v]=fa[v]=u;
			}
		}
		int ans=0;
		for(int i=1;i<=n;i++)
		{
			ans+=a[i]-a[fa[i]];
		}
		cout<<ans<<endl;
	}
	return 0;
}

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