- 开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;
}