1. 程式人生 > 實用技巧 >238. 銀河英雄傳說 AcWing

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 }