(树的重心)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 }

浙公网安备 33010602011771号