spoj Corporative Network
题目描述
原本有 n 个节点,最初每个节点的父亲都是自己。
现在给你若干操作,共分为两种,操作格式如下:
I x y(大写字母I)
将 x 的父亲变为 y,而且令 x 与 y 之间的距离为 \(\lvert x-y \rvert \bmod 1000\) 。
E x 询问x点到其根节点的距离
数据保证对于所有的 1 操作合法,即保证之前 y 不是 x 的父亲、
输入格式
第一行输入一个整数 T,表示每个数据点的数据组数。
接下来对于每组数据输入格式如下:
第一行包含一个正整数 n,表示原有的节点个数
从第二行开始,以下有若干行,每一行的输入格式为
I x y 或E x 分别代表以上的两种操作
对于这些操作,以输入一个O(大写字母O)为终止。
输出格式
一共若干行,表示对于每一组测试数据中的 E 操作输出答案。
输入输出样例
输入
1
4
E 3
I 3 1
E 3
I 1 2
E 3
I 2 4
E 3
O
输出
0
2
3
5
带权并查集
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e4+10;
int f[maxn],dis[maxn];
int t,n;
char s[3];
void join(int x,int y)
{
f[x]=y;
dis[x]+=x>y?((x-y)%1000):((y-x)%1000);
}
int find(int x)
{
if(f[x]==x)return x;
int fa=f[x];
f[x]=find(f[x]);
dis[x]=dis[x]+dis[fa];
return f[x];
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<=n;++i)f[i]=i,dis[i]=0;
int x,y;
do
{
scanf("%s",s);
if(s[0]=='O')break;
if(s[0]=='I')
{
scanf("%d%d",&x,&y);
join(x,y);
}
else
{
scanf("%d",&x);
find(x);
printf("%d\n",dis[x]);
}
}while(1);
}
return 0;
}