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

 

posted @ 2020-11-19 21:44  不敢说的梦  阅读(144)  评论(0)    收藏  举报