Description
Solution
- 考场上没有足够的时间,也并没有打二叉树的,所以只有55分了。。。。
- 首先树的重心有几个性质我居然一直不知道!(虽然题面里面都有提及,但是我居然将它们忽略了)。
1.树的重心当且仅当最大的子树大小小于n/2。如果不是的话可以通过往大于n/2的子树中调整获得更优的答案。再推一下可以发现,当这个时候的重心的最大子树的size为n/2且n为偶数的时候,这个儿子也是一个重心,因此重心只有一个或两个。
2.树的重心一定在包括根节点的重链上。首先求重心有一种我之前一直没有用过的方法,就是从根节点往下逼近,那么如果在逼近的过程中如果往轻儿子走的话,当前最大重儿子的最小size的最大值就己经没有往重儿子走优。
3.根据上面的两个性质,可以得知只需要找到重链上最后一个sz>=n/2的,那么在这个重链以前的都一定满足第一个条件,又因为只有一个或两个,所以取末尾两个对比一下就好哦了。 - 可以用倍增维护重链。
- 换根转移即可。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 300005
#define maxp 20
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
using namespace std;
int T,n,i,j,k,x,y;
int em,e[maxn*2],nx[maxn*2],ls[maxn];
int fa[maxn],sz[maxn],gs[maxn];
int Sz[maxn],Gs[maxn],f[maxn][maxp],F[maxn][maxp];
ll ans;
void read(int &x){
x=0; char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
}
void insert(int x,int y){
em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
}
void DFS(int x,int p){
sz[x]=1,fa[x]=p;
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p){
DFS(e[i],x),sz[x]+=sz[e[i]];
if (!gs[x]||sz[gs[x]]<sz[e[i]])
gs[x]=e[i];
}
f[x][0]=gs[x],Gs[x]=gs[x];
for(int i=1;i<maxp;i++) f[x][i]=f[f[x][i-1]][i-1];
}
void upd(int x){
for(int i=1;i<maxp;i++)
F[x][i]=F[F[x][i-1]][i-1];
}
void Get(int st){
int N=Sz[st];
int y1=st,y2=st,c=0;
for(int i=maxp-1;i>=0;i--) if (F[y1][i]&&Sz[F[y1][i]]>=(N+1)/2)
y1=F[y1][i],c+=1<<i;
if (c){
c--;
for(int i=maxp-1;i>=0;i--) if (c>=(1<<i))
c-=1<<i,y2=F[y2][i];
int mx=min(max(N-Sz[y1],Sz[Gs[y1]]),max(N-Sz[y2],Sz[Gs[y2]]));
if (max(N-Sz[y1],Sz[Gs[y1]])==mx) ans+=y1;
if (max(N-Sz[y2],Sz[Gs[y2]])==mx) ans+=y2;
} else ans+=y1;
}
int totT,To[maxn],pre[maxn],nex[maxn];
void DFS2(int x,int p){
if (x!=1) Get(x);
totT=0;
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p) To[++totT]=e[i];
int mx=To[1];
for(int i=2;i<=totT;i++){
pre[To[i]]=mx;
if (Sz[To[i]]>Sz[mx]) mx=To[i];
}
mx=To[totT];
for(int i=totT-1;i>=1;i--){
nex[To[i]]=mx;
if (Sz[To[i]]>Sz[mx]) mx=To[i];
}
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p){
Gs[x]=fa[x];
if (pre[e[i]]&&Sz[pre[e[i]]]>Sz[Gs[x]]) Gs[x]=pre[e[i]];
if (nex[e[i]]&&Sz[nex[e[i]]]>Sz[Gs[x]]) Gs[x]=nex[e[i]];
F[x][0]=Gs[x],upd(x);
Sz[x]=n-Sz[e[i]];
Get(x);
DFS2(e[i],x);
}
Sz[x]=sz[x],Gs[x]=gs[x];
memcpy(F[x],f[x],sizeof(f[x]));
}
int main(){
freopen("centroid.in","r",stdin);
freopen("centroid.out","w",stdout);
read(T);
while (T--){
read(n),ans=0;
em=0,mem(ls),mem(f),mem(sz),mem(gs),mem(pre),mem(nex);
for(i=1;i<n;i++) read(x),read(y),insert(x,y);
DFS(1,0);
memcpy(Sz,sz,sizeof(sz));
memcpy(F,f,sizeof(F));
DFS2(1,0);
printf("%lld
",ans);
}
}