题意:有N个企业,企业间要进行合作,于是需要连线,I I J表示将I连到J去,即J作为I的父结点,有一系列的询问,E I 表示询问I到根结点的连线距离是多长,输出这个结果。
——>>用并查集连起来即可。主要在于,用d[i]表示从i到根结点的距离,但在初始化后第一次赋值时应为i到其父结点的距离,如果不是的话,可能会出现修改一个结点,则其所有子结点都要修改的繁琐现象。若有1-2-3-4,担心会出现查4时d[4] = d[4] + d[3]而d[3]没改为3到根的距离?不用担心,find是递归,深度优先,在执行d[4] = d[4] + d[3]前已执行为d[3] = d[2] + d[1],更先执行为d[2] = d[2] + d[1]。
#include <iostream>
using namespace std;
const int maxn = 20000 + 10; //企业数5 <= N <= 20000
int d[maxn], fa[maxn]; //d[i]点i到根结点的距离(但初始化后第一次给的值是i到其父结点的距离),fa[i]为结点i的父结点
int find(int x) //带路径压缩的查找函数
{
if(x == fa[x]) return x;
else
{
int root = find(fa[x]);
d[x] += d[fa[x]]; //改为到根的距离,这里不需考虑是否要对1000取模
return fa[x] = root; //路径压缩
}
}
int main()
{
int T, N, i, I, J;
cin>>T;
while(T--)
{
cin>>N;
for(i = 0; i <= N; i++) //初始化
{
fa[i] = i; //根树
d[i] = 0; //自己到自己(根)的距离为0
}
char c;
bool ok = 1; //是否退出的标记
while(ok && cin>>c)
{
switch(c)
{
case 'O':
{
ok = 0;
break;
}
case 'I':
{
cin>>I>>J;
fa[I] = J;
int ans = I > J ? (I-J) : (J-I);
d[I] = ans % 1000; //赋该点到其父结点的距离值
break;
}
case 'E':
{
cin>>I;
find(I); //find会维护(将d[I]改为该点到根的距离)该点到根的距离
cout<<d[I]<<endl;
break;
}
}
}
}
return 0;
}