题目链接
给定一棵树,对于树上每个结点,将它删去,然后你可以将得到的森林中任意一棵树的一个点与其父亲断开并连接到另一颗树上。求森林中所有树 size 最大值的最小值。
先考虑怎么求一个点的答案。令 sizei 表示点 i 的子树和, min 表示森林中最小的树的大小, max 表示森林中最大的树的大小。那么我们可以二分答案 ans ,问题就转化为最大的树中是否存在一个点 i ,使 sizei+min≤ans 且 max−sizei≤ans ,即 max−ans≤sizei≤ans−min 。
注意二分的边界。
从根开始 dfs 一遍,维护 4 个 map :
求点 i 的答案时,判断删去这个点后森林中最大的树是什么:
接下来考虑怎么维护这 4 个 map :
时间复杂度 O(nlogn)
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 100010
#define It map::iterator
vector<int>g[N];
map<int,int>M[4];
int i,j,k,n,m,p,sz[N],Ans[N],s[N],x,y,mn[N],smx[N],Rt;
inline int Min(int x,int y){
return xinline int Max(int x,int y){
return xinline void Dfs1(int x){
sz[x]=1;mn[x]=n;
for(int i=0;iif(sz[g[x][i]]>sz[s[x]])smx[x]=sz[s[x]],s[x]=g[x][i];else
if(sz[g[x][i]]>smx[x])smx[x]=sz[g[x][i]];
}
M[3][sz[x]]++;
if(sz[x]inline void Update(int x,int y,int d){
M[d][x]+=y;M[3][x]-=y;
if(!M[3][x])M[3].erase(x);
if(!M[d][x])M[d].erase(x);
}
inline void Get(int x,int y,int d){
Update(sz[x],y,d);
for(int i=0;iinline int Find(int x,int y,int l,int r,int d,int z){
int Mid;
if(x==y&&x>=l&&x<=r)return x;
while(l<=r){
Mid=l+r>>1;
It t=M[d].lower_bound(y-Mid+z);
if(t!=M[d].end()&&t->first<=Mid-x+z)r=Mid-1;else l=Mid+1;
}
return l;
}
inline void Solve(int x){
if(sz[x]==n)Ans[x]=Find(mn[x],sz[s[x]],smx[x],sz[s[x]],1,0);else
if(sz[s[x]]>n-sz[x])Ans[x]=Find(Min(mn[x],n-sz[x]),sz[s[x]],Max(n-sz[x],smx[x]),sz[s[x]],1,0);else
if(!s[x])Ans[x]=n-sz[x];else Ans[x]=Min(Find(mn[x],n-sz[x],sz[s[x]],n-sz[x],0,sz[x]),Find(mn[x],n-sz[x],sz[s[x]],n-sz[x],3,0));
}
inline void Dfs(int x,bool d){
Update(sz[x],1,0);
for(int i=0;iif(g[x][i]!=s[x])Dfs(g[x][i],0);
if(s[x])Dfs(s[x],1);
for(int i=0;iif(g[x][i]!=s[x])Get(g[x][i],1,2);
if(!(--M[0][sz[x]]))M[0].erase(sz[x]);
Solve(x);
M[3][sz[x]]++;
if(d){
Update(sz[x],1,1);
for(It t=M[2].begin();t!=M[2].end();)
M[1][t->first]+=t->second,M[2].erase(t++);
}else for(int i=0;iif(g[x][i]!=s[x])Get(g[x][i],-1,2);else Get(g[x][i],-1,1);
}
int main(){
scanf("%d",&n);
if(n==1)return putchar(48),0;
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if(x)g[x].push_back(y);else Rt=y;
}
Dfs1(Rt);
Dfs(Rt,1);
for(i=1;i<=n;i++)printf("%d\n",Ans[i]);
return 0;
}