codeforces1406C. Link Cut Centroids 树的重心板子题

1406C 1700
之前没听过树的重心,还以为是离散里面的知识,主要是补充概念
树的重心或者说质心
基本概念:
对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
性质:
1、树中所有节点到重心的距离之和最小,如果有两个重心,那么他们距离之和相等。
2、把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
3、一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
4、删除重心后所得的所有子树,节点数不超过原树的1/2,一棵树最多有两个重心,且相邻。

代码如下:

#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define rep(i, a, n) for(int i = a; i <= n; i++)
#define per(i, a, n) for(int i = n; i >= a; i--)
#define IOS std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fopen freopen("file.in","r",stdin);freopen("file.out","w",stdout);
#define fclose fclose(stdin);fclose(stdout);
const int inf = 1e9;
const ll onf = 1e18;
const int maxn = 1e5+10;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
std::vector<int> g[maxn];
int siz[maxn], wt[maxn], n, ans1, ans2;
void dfs(int u, int pre){
	siz[u] = 1;
	wt[u] = 0;
	for(auto to : g[u]){
		if(to==pre) continue;
		dfs(to, u);
		siz[u] += siz[to];
		wt[u] = max(wt[u], siz[to]);
	}
	wt[u] = max(wt[u], n-siz[u]);
	if(wt[u]<<1<=n){
		ans2 = ans1, ans1 = u;
	}
}
inline void cf(){
	int t = read();
	while(t--){
		n = read();
		rep(i,1,n) g[i].clear(), siz[i]=0, wt[i]=0;
		rep(i,1,n-1){
			int x=read(), y=read();
			g[x].push_back(y), g[y].push_back(x);
		}
		ans1 = ans2 = 0;	
		dfs(1,0);
		if(ans2==0){
			printf("%d %d\n", ans1, g[ans1][0]);
			printf("%d %d\n", ans1, g[ans1][0]);
		}else {
			int i = 0;
			while(ans2==g[ans1][i]&&i<g[ans1].size()) i++;
			printf("%d %d\n", ans1, g[ans1][i]);
			printf("%d %d\n", ans2, g[ans1][i]);
		}
	}
	return ;
}
signed main(){
	cf();
	return 0;
}
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页