238. 银河英雄传说 AcWing
考察: 并查集
通过这道题算是把食物链没搞懂的问题又弄明白了点
很明显根据题意我们需要维护一个距离数组,表示父节点到子节点的距离.
当操作是C的时候,我们实际上在进行C操作之前是进行过路径压缩的,因此d[x]的距离变成了x到根节点的距离,d[y]的距离就算y到根节点的距离,因此两者的距离差就是:
abs(d[x]-d[y])-1
当操作是M的时候,我们在M操作里实际上也进行了路径压缩,但压缩的不是x到父节点的距离,而是父节点到新根节点的距离.题目要求我们将x接到y的尾部,实际上M操作里我们为了配合并查集的Merge操作,是将x结点接到了y的根节点处,而d[px]的距离也被压缩成px到根节点的距离,也就是y集合的大小
那么x结点的距离如何更新?当我们用到x的距离的时候自然就会更新,也就是在find函数里对x距离进行路径压缩
1 #include <iostream> 2 #include <cmath> 3 using namespace std; 4 const int N = 30010; 5 int p[N],d[N],sz[N]; 6 int find(int x) 7 { 8 if(p[x]!=x){ 9 int t = find(p[x]);//这里是将x与父节点的距离压缩成x与根节点的距离 10 d[x]+=d[p[x]]; 11 p[x] = t; 12 } 13 return p[x]; 14 } 15 int main() 16 { 17 int t; 18 char op[2]; 19 scanf("%d",&t); 20 for(int i=1;i<=N-10;i++) { p[i] = i; sz[i] = 1; } 21 while(t--){ 22 int x,y; 23 scanf("%s%d%d",op,&x,&y); 24 int px = find(x); int py = find(y); 25 if(op[0]=='M'){ 26 d[px] = sz[py];//这里实际上也是路径压缩,但是将x的父节点的路径压缩,x与父节点的距离不变 27 sz[py]+=sz[px];//在题意理解上px是跟在y所在列的后面,但实际上合并是跟在y根节点的后面 28 p[px] = py; 29 }else if(op[0]=='C'){ 30 if(px!=py) printf("-1\n"); 31 else printf("%d\n",abs(d[x]-d[y])-1); 32 } 33 } 34 return 0; 35 }