洛谷 P5666 树的重心

洛谷 P5666 树的重心

https://www.luogu.com.cn/problem/P5666

Snipaste_2020-06-29_08-58-13.png

Snipaste_2020-06-29_08-58-25.png

Tutorial

https://www.luogu.com.cn/blog/soaring/solution-p5666

关于树的重心有一条性质,假如\(u\)不是重心,那么重心一定在\(u\)的size最大的子树中.

利用这个性质我们可以利用倍增的思想快速找到重心.即维护\(jump(u,i)\)表示从\(u\)出发,向重儿子走\(2^i\)步所到达的节点.

由于要对于每条边统计,所以用换根dp的思想,在dfs的时候维护以当前节点为根时的\(jump\)等信息即可.

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
inline char nc() {
	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void read(T &x) {
	x=0; int f=1,ch=nc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
	x*=f;
}
typedef long long ll;
const int maxn=299995+50;
int T,n;
int head[maxn];
int anc[maxn],siz[maxn],son[maxn][2];
int pre[maxn],s[maxn],jump[maxn][20];
ll an;
struct edge {
	int to,nex;
	edge(int to=0,int nex=0):to(to),nex(nex){}
}; 
vector<edge> G;
inline void addedge(int u,int v) {
	G.push_back(edge(v,head[u])),head[u]=G.size()-1;
	G.push_back(edge(u,head[v])),head[v]=G.size()-1;
}
void dfs0(int u) {
	siz[u]=1,son[u][0]=son[u][1]=0;
	for(int i=head[u];~i;i=G[i].nex) {
		int v=G[i].to; if(v==anc[u]) continue;
		anc[v]=u;
		dfs0(v);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u][0]]) son[u][1]=son[u][0],son[u][0]=v;
		else if(siz[v]>siz[son[u][1]]) son[u][1]=v;
	}
	pre[u]=anc[u],s[u]=siz[u],jump[u][0]=son[u][0];
	for(int i=1;i<20;++i) jump[u][i]=jump[jump[u][i-1]][i-1];
}
inline int check(int x,int r) {
	if(s[jump[x][0]]>s[r]/2) return 0;
	return x;
}
void sol(int u) {
	int x=u;
	for(int i=19;~i;--i) if(s[u]-s[jump[x][i]]<=s[u]/2) x=jump[x][i];
	an+=check(x,u)+check(pre[x],u);
}
void dfs1(int u) {
	for(int i=head[u];~i;i=G[i].nex) {
		int v=G[i].to; if(v==anc[u]) continue;
		pre[u]=pre[v]=0,s[u]=n-siz[v];
		jump[u][0]=son[u][v==son[u][0]];
		if(n-siz[u]>siz[jump[u][0]]) jump[u][0]=anc[u];
		for(int j=1;j<20;++j) jump[u][j]=jump[jump[u][j-1]][j-1];
		sol(u),sol(v);
		pre[u]=v;
		dfs1(v);
	}
	pre[u]=anc[u],s[u]=siz[u],jump[u][0]=son[u][0];
	for(int i=1;i<20;++i) jump[u][i]=jump[jump[u][i-1]][i-1];
}
int main() {
	read(T);
	for(int kase=1;kase<=T;++kase) {
		read(n);
		memset(head,-1,sizeof(head)),G.clear();
		for(int i=1;i<n;++i) {
			int u,v; read(u),read(v);
			addedge(u,v);
		}
		an=0;
		dfs0(1);
		dfs1(1);
		printf("%lld\n",an);
	}
	return 0;
} 
posted @ 2020-06-29 09:05  LJZ_C  阅读(246)  评论(0编辑  收藏  举报