这种类型的并查集不仅要压缩路径,而且每次在压缩路径的时候要更新每个点到树根的距离,每次只把一个集合的根与另一个集合的一个元素连边,距离都是在访问的时候更新的。
一开始还是不太会写,不过思想应该理解啦~~~
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxn 20005
#define INF 0xfffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define FOR(i,s,t) for(int i=s;i<=t;i++)
#define ull unsigned long long
#define ll long long
using namespace std;
char s[5];
int f[maxn],d[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)
{
f[i]=i;
d[i]=0;
}
}
//这个findset()函数开始有点难理解,不过画图之后就好理解了
int findset(int x)//路径压缩,同时维护d[i]:结点到树根的距离
{
if(x!=f[x])
{
int root=findset(f[x]);
d[x]+=d[f[x]];
return f[x]=root;
}
else
{
return x;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
init(n);
while(scanf("%s",s)!=EOF)
{
if(s[0]=='O') break;
int u,v;
if(s[0]=='E')
{
scanf("%d",&u);
findset(u);
printf("%d\n",d[u]);
}
else
{
scanf("%d%d",&u,&v);
f[u]=v,d[u]=abs(u-v)%1000;
}
}
}
return 0;
}