238. 銀河英雄傳說 AcWing
阿新 • • 發佈:2021-01-03
考察: 並查集
通過這道題算是把食物鏈沒搞懂的問題又弄明白了點
很明顯根據題意我們需要維護一個距離陣列,表示父節點到子節點的距離.
當操作是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); intpy = 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 }