题解 P2018 【消息传递】
这里主要介绍一个
虽然对于这道题
首先可以想出这道题对于一个确定的根的
再以任意点
我们设
当
其中
很容易想到贪心,我们让
单次复杂度
但这样做需要枚举根,最终复杂度
瓶颈在于什么,仔细思考我们会发现其实是我们确定了向“下”传的顺序,而因此很多子树的信息在不同的根下实际上是一样的
什么意思,我们看一下这幅图
在
我们有没有办法一次计算这些信息呢
有的,那就是所谓的二次扫描与换根法
在李煜东的书里介绍了这个算法并给出了一个例题,但这个例题会更为复杂一些
我先重复一下这个算法流程
- 一次树形dp,求出每个点以
root 为根的子树中信息down - 一次DFS求出每个点以
root 为根来自父亲的信息up ,同时合并up 和down
我们用这道题来看如何实现
对于
设
我们在计算完了
用这幅图理解一下,
注意一下:为了处理方便,我们并不一开始显式去掉
inline void change_root(re int x){
re int i,y,pos;re vector<int> son;
for(i=h[x];i;i=e[i].next){y=e[i].to;son.push_back(dpson[y]);}if(fa[x])son.push_back(dpfa[x]);
sort(son.begin(),son.end(),cmp);
for(i=0;i<(int)son.size();++i)t[i]=son[i]+i+1;
*maxl=t[0];for(i=1;i<(int)son.size();++i)maxl[i]=max(maxl[i-1],t[i]);
maxr[son.size()-1]=t[son.size()-1];for(i=son.size()-2;i>=0;--i)maxr[i]=max(maxr[i+1],t[i]);
reverse(son.begin(),son.end());
for(i=h[x];i;i=e[i].next){
y=e[i].to;
pos=lower_bound(son.begin(),son.end(),dpson[y])-son.begin();pos=son.size()-pos-1;
if(!pos)dpfa[y]=max(0,maxr[1]-1);
else if(pos==(int)son.size()-1)dpfa[y]=max(0,maxl[pos-1]);
dpfa[y]=max(maxl[pos-1],maxr[pos+1]-1);
}
dp[x]=maxl[son.size()-1];for(i=h[x];i;i=e[i].next){y=e[i].to;change_root(y);}
}
其他细节比如边界什么的需要做了才知道
#include<bits/stdc++.h>
#define N 200005
#define re register
#define INF 0x3f3f3f3f
using namespace std;
struct read{
char buf[1<<25],*opt;
read():opt(buf){buf[fread(buf,1,sizeof buf,stdin)]=0;}
template<typename _int>
operator _int(){
_int res=0,flag=1;
while(*opt<48&&*opt!='-')++opt;
if(*opt=='-'){flag=-1;++opt;}
while(*opt>32)res=(res<<1)+(res<<3)+(*opt++)-48;
return res*flag;
}
}it;
inline char cmp(re int x,re int y){return y<x;}
struct Edge{int to,next;}e[N<<1];
int n,cnt,h[N],t[N],dpson[N],dpfa[N],maxl[N],maxr[N],fa[N],dp[N],ans=INF,Ans[N];
inline void AddEdge(re int x,re int y){e[++cnt]=(Edge){y,h[x]};h[x]=cnt;}
inline void tree_dp(re int x){
re int i,y,res=0;re vector<int> son;
for(i=h[x];i;i=e[i].next){
y=e[i].to;
tree_dp(y);
son.push_back(dpson[y]);
}
sort(son.begin(),son.end(),cmp);
for(i=0;i<(int)son.size();++i)res=max(res,son[i]+i+1);
dpson[x]=res;
}
inline void change_root(re int x){
re int i,y,pos;re vector<int> son;
for(i=h[x];i;i=e[i].next){y=e[i].to;son.push_back(dpson[y]);}if(fa[x])son.push_back(dpfa[x]);
sort(son.begin(),son.end(),cmp);
for(i=0;i<(int)son.size();++i)t[i]=son[i]+i+1;
*maxl=t[0];for(i=1;i<(int)son.size();++i)maxl[i]=max(maxl[i-1],t[i]);
maxr[son.size()-1]=t[son.size()-1];for(i=son.size()-2;i>=0;--i)maxr[i]=max(maxr[i+1],t[i]);
reverse(son.begin(),son.end());
for(i=h[x];i;i=e[i].next){
y=e[i].to;
pos=lower_bound(son.begin(),son.end(),dpson[y])-son.begin();pos=son.size()-pos-1;
if(!pos)dpfa[y]=max(0,maxr[1]-1);
else if(pos==(int)son.size()-1)dpfa[y]=max(0,maxl[pos-1]);
else dpfa[y]=max(maxl[pos-1],maxr[pos+1]-1);
}
dp[x]=maxl[son.size()-1];for(i=h[x];i;i=e[i].next){y=e[i].to;change_root(y);}
}
int main(void){
n=it;
re int i;
for(i=2;i<=n;++i){fa[i]=it;AddEdge(fa[i],i);}
tree_dp(1);change_root(1);
for(i=1;i<=n;++i)if(dp[i]<ans){ans=dp[i];Ans[*Ans=1]=i;}else if(ans==dp[i])Ans[++*Ans]=i;
printf("%d\n",ans+1);
for(i=1;i<=*Ans;++i)printf("%d ",Ans[i]);
return 0;
}