1. 程式人生 > 實用技巧 >(樹的重心)CF1406C Link Cut Centroids

(樹的重心)CF1406C Link Cut Centroids

題目連結:CF1406C

樹的重心性質:https://www.cnblogs.com/suxxsfe/p/13543253.html (by suxxsfe)

題目大意:

給一棵樹,如果有兩個重心,則通過一次刪邊加邊,使樹只有一個重心。

性質:

1. 樹的重心如果不唯一,則至多有兩個,且這兩個重心相鄰

2. 一個點是重心,等價於,以這個點為根,它的每個子樹的大小,都不會超過整個樹大小的一半

3. 樹中所有點到某個點的距離和中,到重心的距離和是最小的。如果有兩個重心,那麼到它們的距離和一樣。更進一步,距離和最小與是重心等價

4. 如果一個樹增添,或刪去一個葉子,則整個樹的同一個重心最多移動一個節點

5.如果一個樹增添,或刪去一個葉子,則整個樹的同一個重心最多移動一個節點

6.通過連線一條端點分別在兩個樹的邊,來將兩個樹合併成一個,那麼新的重心肯定是在原來這兩個樹的重心的路徑上

參考程式碼:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #define N 100010
 6 using namespace std;
 7 int n,u,v,son[N],cen[2],bal;
 8 vector<int
> g[N]; 9 void dfs(int u, int fa) { 10 son[u] = 1; 11 int w = 0; 12 for(int i: g[u]) { 13 if(i == fa) continue; 14 dfs(i,u); 15 son[u] += son[i]; 16 w = max(w,son[i]); 17 } 18 w = max(w,n-son[u]); 19 if(w < bal) 20 bal = w,cen[0] = u,cen[1
] = 0; 21 else if(w == bal) cen[1] = u; 22 } 23 int main() { 24 int t; 25 cin >> t; 26 while(t--) 27 { 28 cin >> n; bal = N+10; cen[0] = cen[1] = 0; 29 memset(son,0,sizeof(son)); 30 for(int i = 0; i <= n; i++) g[i].clear(); 31 for(int i = 0; i < n-1; i++) { 32 scanf("%d%d",&u,&v); 33 g[u].push_back(v); 34 g[v].push_back(u); 35 } 36 dfs(1,0); 37 if(cen[1] == 0) { 38 printf("1 %d\n1 %d\n",g[1][0],g[1][0]); 39 continue; 40 } 41 for(int i:g[cen[0]]) { 42 if(i != cen[1]) { 43 printf("%d %d\n%d %d\n",cen[0],i,cen[1],i); 44 break; 45 } 46 } 47 } 48 return 0; 49 }