Discription:

断开树的每一个点会形成一个森林,然后可以进行一次操作:将森林中的一棵树接到另一棵树上。使得森林中size最大的树size最小。依次输出对于每个结点的最小size值

Hint:

\(n<=1e5\)

Solution:

用multiset维护每个点的size域,每次贪心将最大的树的子树接到最小的树上,答案用二分答案求出

本题细节较多,需要处理各种情况

#include<bits/stdc++.h>
using namespace std;
typedef multiset<int >::iterator mit;
const int mxn=1e5+5;
struct ed {
int to,nxt;
}t[mxn];
int n,rt,cnt;
int hd[mxn],sz[mxn],f[mxn],son[mxn],ans[mxn];
multiset<int >mp[mxn],oth,anc; inline void add(int u,int v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
} void dfs1(int u)
{
sz[u]=1;
for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
dfs1(v); sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
if(u!=rt) oth.insert(sz[u]);
} //第一遍Dfs预处理出重儿子和初始size inline int check(int opt,int val,int u,int mi,int mx)
{
if(opt) {
mit tp=mp[son[u]].lower_bound(mx-val);
if(tp!=mp[son[u]].end()&&(*tp)+mi<=val) return 1;
}
else {
mit tp=oth.lower_bound(mx-val);
if(tp!=oth.end()&&(*tp)+mi<=val) return 1;
tp=anc.lower_bound(mx-val+sz[u]);
if(tp!=anc.end()&&(*tp)+mi-sz[u]<=val) return 1;
}
return 0;
} //分类讨论检验答案 void dfs2(int u)
{
if(u!=rt) oth.erase(oth.lower_bound(sz[u])); //一开始删除,后面会加进来
if(f[u]&&f[u]!=rt) anc.insert(sz[f[u]]);
//因为祖先size是变化的,故将祖先单独拿出来维护
int mx1=max(n-sz[u],sz[son[u]]); //子树size的最大值
int mx2=min(n-sz[u],sz[son[u]]); //子树size的次大值
int mi=n-sz[u]; //子树size的最小值
if(!mi) mi=sz[son[u]];
for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
if(v==son[u]) continue ;
dfs2(v);
for(mit it=mp[v].begin();it!=mp[v].end();++it)
oth.insert(*it);
mi=min(mi,sz[v]),mx2=max(mx2,sz[v]);
}
if(son[u]) dfs2(son[u]),mi=min(mi,sz[son[u]]);
for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
if(v==son[u]) continue ;
for(mit it=mp[v].begin();it!=mp[v].end();++it)
oth.erase(oth.lower_bound(*it));
}
if(mx1!=mx2) {
int l=mx2,r=mx1;
int opt=(mx1==sz[son[u]]);
while(l<=r) {
int mid=(l+r)>>1;
if(check(opt,mid,u,mi,mx1)) ans[u]=mid,r=mid-1;
else l=mid+1;
}
} //当操作有意义时,二分答案
if(!ans[u]) ans[u]=mx1;
if(son[u]) swap(mp[u],mp[son[u]]);
//每次直接O(1)继承重儿子的set,从而保证了时间复杂度 for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
if(v==son[u]) continue ;
for(mit it=mp[v].begin();it!=mp[v].end();mp[v].erase(it++))
mp[u].insert(*it);
}
if(f[u]&&f[u]!=rt) anc.erase(anc.lower_bound(sz[f[u]]));
mp[u].insert(sz[u]);
} void solve()
{
dfs2(rt);
for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
} int main()
{
int u,v;
scanf("%d",&n);
for(int i=1;i<=n;++i) {
scanf("%d %d",&u,&v);
if(!u) rt=v;
else add(u,v),f[v]=u;
}
dfs1(rt); solve();
return 0;
}

最新文章

  1. PNG和Gif及JPEG图片格式比较
  2. AngularJs的UI组件ui-Bootstrap分享(五)——Pager和Pagination
  3. Java、Android 开发环境搭建
  4. c#开发Mongo笔记第四篇
  5. Turing Test
  6. paper 80 :目标检测的图像特征提取之(一)HOG特征
  7. Difference Between Vector and Deque in C++
  8. HDU 5878 I Count Two Three
  9. 通过startup启动tomcat一闪而过的问题
  10. C#.NET Split 的几种使用方法
  11. oracle exp实例
  12. Vim的常用命令笔记
  13. 老李分享:Web Services 组件 1
  14. 弱校ACM奋斗史
  15. Java IO系列之二:NIO基本操作
  16. Anaconda+MINGW+theano+keras安装
  17. Linux命令模拟Http的get或post请求
  18. go语言fallthrough的用法心得
  19. 吴裕雄 python深度学习与实践(13)
  20. Memcached和Memcache安装(64位win2008)

热门文章

  1. 总结Java虚拟机内存区域模型
  2. 步步为营-75-Cookie简介
  3. IEDA序列化设置
  4. ERP系统
  5. OpenCV-Python教程8-图像混合
  6. 使用jquery.more.js上滑加载更多
  7. 10个财务工作中常用的 Excel 万能公式
  8. OpenGL搭建环境-VS2012【OpenGL】
  9. zabbix通过shell脚本安装异常问题定位
  10. PUTTY工具的使用