有n个结点(编号为1..n),初始时每个结点的父亲都不存在。你的任务是执行一次I操作和E操作,格式如下:
I u v:把节点u的父亲点设置为v,距离为|u-v|除以1000的余数。输入保证执行指令前u没有父亲节点。
E u:询问u 到根接点的距离(输出距离 mod 1000的结果)。
【输入格式】
输入第一行为测试数据组数T。每组数据第一行为n(5<=n<=20 000)。接下来有不超过20000行,每一行一条指令,以"O"结尾。I指令的个数不小于n。
【输出格式】
对于每条E指令,输出查询结果。
并查集的路径压缩时维护点到根的距离
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define ll long long using namespace std; const int maxn=20010; inline int read(){ int x=0,k=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return k*x; } int f[maxn],d[maxn]; int find(int x){ if(f[x]!=x){ int root=find(f[x]); d[x]+=d[f[x]]; return f[x]=root; } else return x; } int main(){ int t,n,u,v; t=read(); while(t--){ n=read(); for(int i=1;i<=n;i++) f[i]=i,d[i]=0; char c[5]; while(cin>>c&&c[0]!='O'){ if(c[0]=='I'){ u=read();v=read(); f[u]=v; d[u]=abs(u-v)%1000; } else{ u=read(); find(u); cout<<d[u]<<endl; } } } return 0; }