<题目链接>
题目大意:
n个节点,若干次询问,I x y表示从x连一条边到y,权值为|x-y|%1000;E x表示询问x到x所指向的终点的距离。
解题分析:
与普通的带权并查集类似,但是要注意的是,在进行查询操作时,也要调用一下find函数,因为以前的uion操作可能将某些值改变了,所以find()操作是将这些节点全部更新一遍,得到它们的真实值。
#include <cstdio> #include <cmath> const int maxn=20000+100; int father[maxn],dis[maxn]; int n; int find(int x){ if(father[x]==x) return x; int temp=father[x]; father[x]=find(father[x]); dis[x]=dis[x]+dis[temp]; //x到根节点的距离=x到父亲的距离+父亲到根节点的距离。不能交换这句和上一句的顺序,否则dis[x]就表现不了到新根的距离了 return father[x]; } void Uion(int a,int b){ int ra=find(a); int rb=find(b); if(ra!=rb){ father[ra]=rb; dis[ra]=(abs(a-b)%1000-dis[a]+dis[b]); //根据矢量,得出ra到rb的距离 } } int main(){ int t;scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++){ father[i]=i; dis[i]=0; } getchar(); char ch; while(scanf("%c",&ch)){ if(ch=='O')break; if(ch=='I'){ int a,b; scanf("%d %d",&a,&b); Uion(a,b); getchar(); } else{ int a; scanf("%d",&a); find(a); //注意这里,查询的时候也要压缩一下,因为uion操作会更新dis数据 printf("%d ",dis[a]); getchar(); } } } return 0; }
2018-08-19