spoj Corporative Network

题目描述

原本有 n 个节点,最初每个节点的父亲都是自己。

现在给你若干操作,共分为两种,操作格式如下:

I x y(大写字母I)
将 x 的父亲变为 y,而且令 x 与 y 之间的距离为 (lvert x-y vert mod 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
",dis[x]);
			}
		}while(1);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/gryzy/p/15164803.html