cats 的最小生成树

题目链接

  • 开300000个并查集固然会空间超限,但考虑到每个并查集内部都存在着大量的空间浪费,因此你完全可以实现“动态开点”并查集
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int fa[700005],s[700005],u[300005],v[300005],ans[300005];
unordered_map<long long,int>V;
int get(int x)
{
	if(fa[x]==x)
	{
		return x;
	}
	return fa[x]=get(fa[x]);
}
void merge(int u,int v)
{
	s[get(v)]+=s[get(u)];
	fa[get(u)]=get(v);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		long long n,m;
		cin>>n>>m;
		for(int i=1;i<=m;i++)
		{
			cin>>u[i]>>v[i];
		}
		int tot=n;
		for(int i=1;i<=n+2*m;i++)
		{
			fa[i]=i;
			s[i]=1;
		}
		V.clear();
		for(int p=1;p<=m;p++)
		{
			if(get(u[p])!=get(v[p]))
			{
				merge(u[p],v[p]);
				ans[p]=1;
				continue;
			}
			int cur=0;
			for(int i=18;i>=0;i--)
			{
				long long x=u[p]+(cur+(1<<i))*n;
				long long y=v[p]+(cur+(1<<i))*n;
				if(V.find(x)==V.end())
				{
					continue;
				}
				if(V.find(y)==V.end())
				{
					continue;
				}
				if(get(V[x])==get(V[y]))
				{
					cur+=(1<<i);
				}
			}
			cur++;
			long long x=u[p]+cur*n;
			long long y=v[p]+cur*n;
			if(V.find(x)==V.end())
			{
				tot++;
				V[x]=tot;
			}
			if(V.find(y)==V.end())
			{
				tot++;
				V[y]=tot;
			}
			merge(V[x],V[y]);
			ans[p]=cur+1;
		}
		for(int i=1;i<=m;i++)
		{
			if(ans[i]==1&&s[get(1)]!=n||ans[i]>1&&s[get(V[1+(ans[i]-1)*n])]!=n)
			{
				ans[i]=-1;
			}
			if(i!=1)
			{
				cout<<" ";
			}
			cout<<ans[i];
		}
		cout<<endl;
	}
	return 0;
}
posted @ 2024-08-26 20:03  D06  阅读(5)  评论(0编辑  收藏  举报