题解[P5666树的重心]
Posted Y_B_X
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解[P5666树的重心]相关的知识,希望对你有一定的参考价值。
题意:给定一棵树,求删去每条边后分裂成的两棵树的重心的编号和之和。
\\(\\text{Solution}\\):
对每个点 \\(x\\) 分开讨论,统计有多少条边割掉后 \\(x\\) 能成为重心。
\\(\\text{Part 1}\\) : 理论分析
假设让 \\(x\\) 成为根,其最大子树大小为 \\(mx\\) , 次大子树大小为 \\(mx1\\)
第一种情况:不在最大子树中割边
这样割后 \\(x\\) 的最大子树为必为 \\(mx\\)
设割去一个子树,其大小为 \\(t\\) ,则与 \\(x\\) 连通的树大小为 \\(n-t\\)
则 \\(x\\) 能成为重心就有 \\(mx \\leq \\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\) ,即 \\(t\\leq n-2mx\\)
第二种情况:在最大子树中割边
割后形成的最大子树大小是 \\(\\max(mx1,mx-t)\\)
所以有 \\(\\max(mx1,mx-t)\\leq\\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\) ,真正统计时可分类讨论 \\(\\max\\) 中那个大得解。
\\(\\text{Part 2}\\) : 实际实现
实际中上述 “换根” 并没法很好维护,需重新分类讨论。
以下将要按照最大子树是否在 \\(x\\) 的子树内,以及割的子树是在 \\(x\\) 子树内,或是 \\(x\\) 到根的路径上,或除去 \\(x\\) 的子树以及 \\(x\\) 到根的路径上的位置进行讨论:
\\(1\\):重儿子在 \\(x\\) 子树内:
\\(\\text{ }\\) \\(1.1\\):割的子树不在 \\(x\\) 的重儿子的子树内:
\\(\\text{ }\\) \\(\\text{ }\\) 此时分后 \\(x\\) 的最大儿子子树大小是 \\(mx\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(1.1.1\\): 割的子树在 \\(x\\) 的子树内:
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) \\(x\\) 所在的分后的树大小为 \\(n-t\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 则 \\(mx \\leq \\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\) ,即 \\(t\\leq n-2mx\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(1.1.2\\): 割的子树在 \\(x\\) 到根的路径上:
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 注意此时 \\(x\\) 所在的分后的树大小变成 \\(t\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 所以 \\(mx\\leq \\left\\lfloor\\frac{t}{2}\\right\\rfloor\\) ,即 \\(t\\geq 2mx\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(1.1.3\\): 割的子树在非 \\(x\\) 子树内且不在 \\(x\\) 到根路径上的其他位置:
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 此时 \\(x\\) 所在的分后的树大小是 \\(n-t\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 与 \\(1.1.1\\) 一样 \\(t\\leq n-2mx\\)
\\(\\text{ }\\) \\(1.2\\): 割的子树在 \\(x\\) 的重儿子内:
\\(\\text{ }\\) \\(\\text{ }\\) 此时分后 \\(x\\) 最大儿子子树大小为 \\(\\max(mx1,mx-t)\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(x\\) 所在分后的树大小为 \\(n-t\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(1.2.1\\) \\(mx-t\\leq mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 此时 \\(t\\geq mx-mx1\\) 且 \\(mx1 \\leq \\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 解得 \\(mx-mx1\\leq t\\leq n-2mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(1.2.2\\) \\(mx-t>mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 此时 \\(t\\leq mx-mx1-1\\) 且 \\(mx-t\\leq \\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 解得 \\(2mx-n\\leq t\\leq mx-mx1-1\\)
\\(2.\\) 重儿子在 \\(x\\) 上方
\\(\\text{ }\\) 此时 \\(mx=n-size(x)\\) , \\(size(x)\\) 为 \\(x\\) 的子树大小
\\(\\text{ }\\) \\(2.1\\) 不在重儿子内割
\\(\\text{ }\\) \\(\\text{ }\\) 此时相当于只在 \\(x\\) 的子树内割
\\(\\text{ }\\) \\(\\text{ }\\) 割后 \\(x\\) 所在的树大小为 \\(n-t\\) ,最大儿子子树大小为 \\(mx\\)
\\(\\text{ }\\) \\(\\text{ }\\) 所以 \\(mx\\leq \\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\) ,即 \\(t\\leq n-2mx=2size(x)-n\\)
\\(\\text{ }\\) \\(2.2\\) 不在 \\(x\\) 子树内且不在 \\(x\\) 到根的路径上割
\\(\\text{ }\\) \\(\\text{ }\\) 此时割后 \\(x\\) 所在树的大小为 \\(n-t\\) ,
\\(\\text{ }\\) \\(\\text{ }\\) 最大儿子子树大小为 \\(\\max(mx-t,mx1)\\leq \\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(2.2.1\\) \\(mx-t\\leq mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 此时 \\(mx-mx1\\leq t\\) 且 \\(mx1\\leq \\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 解得 \\(n-size(x)-mx1\\leq t\\leq n-2mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(2.2.2\\) \\(mx-t>mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 此时 \\(t\\leq mx-mx1-1\\) 且 \\(mx-t\\leq\\left\\lfloor\\frac{n-t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 解得 \\(2mx-n\\leq t\\leq mx-mx1-1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 也即 \\(n-2size(x)\\leq t\\leq n-size(x)-mx1-1\\)
\\(\\text{ }\\) \\(2.3\\) 在 \\(x\\) 到根的路径上割
\\(\\text{ }\\) \\(\\text{ }\\) 此时割后 \\(x\\) 所在的子树大小为 \\(t\\)
\\(\\text{ }\\) \\(\\text{ }\\) 最大儿子子树大小为 \\(\\max(t-size(x),mx1)\\leq \\left\\lfloor\\frac{t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(2.3.1\\) \\(t-size(x)\\leq mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) 此时 \\(t\\leq mx1+size(x)\\) 且 \\(mx1\\leq \\left\\lfloor\\frac{t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) 解得 \\(2mx1\\leq t\\leq mx1+size(x)\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(2.3.2\\) \\(t-size(x)>mx1\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 此时 \\(size(x)+mx1+1\\leq t\\) 且 \\(t-size(x)\\leq \\left\\lfloor\\frac{t}{2}\\right\\rfloor\\)
\\(\\text{ }\\) \\(\\text{ }\\) \\(\\text{ }\\) 解得 \\(size(x)+mx1+1\\leq t\\leq 2size(x)\\)
一长坨的分类讨论到此结束,考虑如何统计每种情况:
对于查 \\(x\\) 的子树的信息,可以以子树大小为权值, \\(\\text{dfs}\\) 序为根的编号建一颗主席树。
对于查 \\(x\\) 到根的信息,可以以子树大小为权值,每次从其父亲更新过来,建成另一棵主席树。
注意 \\(x\\) 的子树大小不必加进来,到其儿子的版本再加。
这样不在 \\(x\\) 子树内且不在 \\(x\\) 到根路径上的信息,可转化为不在 \\(x\\) 子树内的信息减去 \\(x\\) 到根的信息,这两颗主席树足以胜任。
时空复杂度都是 \\(O(n\\log n)\\),由于分类讨论众多,常数略大。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,M=1e7+10;
int T,n,m,x,y,tot,edg,tt,lim,_lim,tmp,res;long long ans;
int to[N<<1],nextn[N<<1],h[N];char ch;
struct tree{int l,r,s;}t[M<<1];
int dfn[N],rev[N],size[N],son[N],mxsz[N],rt[N],rt1[N];
#define add(x,y) to[++edg]=y,nextn[edg]=h[x],h[x]=edg
inline void read(int &x){
x=0;ch=getchar();
while(ch<48||ch>57)ch=getchar();
while(ch>47&&ch<58)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
void write(long long x){if(x>9)write(x/10);putchar(48+x%10);}
void update(int &k,int kk,int l,int r,int pos){
k=++tot;t[k]=t[kk];++t[k].s;
if(l^r){
int mid=(l+r)>>1;
if(pos<=mid)update(t[k].l,t[kk].l,l,mid,pos);
else update(t[k].r,t[kk].r,mid+1,r,pos);
}
}
void inquiry(int k1,int k2,int l,int r,int x,int y){
if(x<=l&&r<=y)res+=t[k2].s-t[k1].s;
else {
int mid=(l+r)>>1;
if(x<=mid)inquiry(t[k1].l,t[k2].l,l,mid,x,y);
if(mid<y)inquiry(t[k1].r,t[k2].r,mid+1,r,x,y);
}
}
void inquiry1(int k,int l,int r,int x,int y){
if(x<=l&&r<=y)res+=t[k].s;
else {
int mid=(l+r)>>1;
if(x<=mid)inquiry1(t[k].l,l,mid,x,y);
if(mid<y)inquiry1(t[k].r,mid+1,r,x,y);
}
}
void dfs(int x,int anc){
int i,y;rev[dfn[x]=++tt]=x;size[x]=1;
for(i=h[x];y=to[i],i;i=nextn[i])if(y^anc){
dfs(y,x);
size[x]+=size[y];
if(size[y]>=size[son[x]])mxsz[x]=size[son[x]],son[x]=y;
else if(size[y]>=mxsz[x])mxsz[x]=size[y];
}
if(n-size[x]>=size[son[x]])mxsz[x]=size[son[x]],son[x]=-1;
else if(n-size[x]>=mxsz[x])mxsz[x]=n-size[x];
}
void dfs_(int x,int anc){
if(anc>1)update(rt1[x],rt1[anc],1,n,size[anc]);int i,y;
for(i=h[x];y=to[i],i;i=nextn[i])if(y^anc)dfs_(y,x);
}
void inq(int x){
res=0;inquiry(rt[0],rt[dfn[x]-1],1,n,lim,_lim);tmp+=res;
res=0;inquiry(rt[dfn[x]+size[x]-1],rt[n],1,n,lim,_lim);tmp+=res;
res=0;inquiry1(rt1[x],1,n,lim,_lim);tmp-=res;
}
main(){
read(T);register int i;
while(T--){
read(n);
for(i=1;i^n;++i)read(x),read(y),add(x,y),add(y,x);
dfs(1,0);
for(i=2;i<=n;++i)update(rt[i],rt[i-1],1,n,size[rev[i]]);
dfs_(1,0);
for(x=1;x<=n;++x){
tmp=res=0;
if(son[x]<0){
lim=(size[x]<<1)-n;
if(lim>0)inquiry(rt[dfn[x]],rt[dfn[x]+size[x]-1],1,n,1,lim),tmp=res;
lim=max(n-size[x]-mxsz[x],1);_lim=n-(mxsz[x]<<1);
if(lim<=_lim)inq(x);
lim=max(n-(size[x]<<1),1);_lim=n-size[x]-mxsz[x]-1;
if(lim<=_lim)inq(x);
lim=(mxsz[x]<<1);_lim=mxsz[x]+size[x];res=0;
if(lim<=_lim)inquiry1(rt1[x],1,n,lim,_lim),tmp+=res;
lim=mxsz[x]+size[x]+1;_lim=(size[x]<<1);res=0;
if(lim<=_lim)inquiry1(rt1[x],1,n,lim,_lim),tmp+=res;
if(mxsz[x]<=(size[x]>>1))++tmp;
}
else {
y=son[x];lim=n-(size[y]<<1);
if(lim>0){
res=0;inquiry(rt[dfn[x]],rt[dfn[y]-1],1,n,1,lim);tmp=res;
res=0;inquiry(rt[dfn[y]+size[y]-1],rt[dfn[x]+size[x]-1],1,n,1,lim);tmp+=res;
res=0;inquiry(rt[0],rt[dfn[x]-1],1,n,1,lim);tmp+=res;
res=0;inquiry(rt[dfn[x]+size[x]-1],rt[n],1,n,1,lim);tmp+=res;
res=0;inquiry1(rt1[x],1,n,1,lim);tmp-=res;
}
res=0;lim=min(size[y]<<1,n);
inquiry1(rt1[x],1,n,lim,n);tmp+=res;
if(size[y]<=(size[x]>>1)&&x^1)++tmp;
lim=max(size[y]-mxsz[x],1);_lim=n-(mxsz[x]<<1);res=0;
if(lim<=_lim)inquiry(rt[dfn[y]-1],rt[dfn[y]+size[y]-1],1,n,lim,_lim),tmp+=res;
lim=max((size[y]<<1)-n,1);_lim=size[y]-mxsz[x]-1;res=0;
if(lim<=_lim)inquiry(rt[dfn[y]-1],rt[dfn[y]+size[y]-1],1,n,lim,_lim),tmp+=res;
}
ans+=1ll*tmp*x;
}
write(ans);putchar(\'\\n\');
for(i=1;i<=n;++i)h[i]=size[i]=mxsz[i]=son[i]=rt[i]=rt1[i]=0;
for(i=1;i<=tot;++i)t[i].l=t[i].r=t[i].s=0;
tot=edg=ans=tt=0;
}
}
以上是关于题解[P5666树的重心]的主要内容,如果未能解决你的问题,请参考以下文章