P3596 [POI 2015 R3] 高速公路现代化 Highway modernization
首先对于最大值,很容易想到找一条边拆掉,然后把两个直径相连,此时最长直径就是两个树的直径和再加一。
而对于最小值,我们将拆出来的两个树找中点,把中点连起来,此时就是两个的直径折半向上取整的和加一以及两个树的直径的最大值。
现在问题就是如何处理一条边两端的树的直径了。
我们首先可以一次 dp 以 \(1\) 为根处理每一个子树的直径。
此时我们在拆边时就可以处理出一端的直径了,有根的一端有以下几种可能:
-
在兄弟节点的子树中,此时需要预处理儿子的最大和次大直径。
-
由两个经过以兄弟为根且经过兄弟的链组合成,此时需要维护这一链的最大次大和次次大值。
-
在上面,直接继承上一次的结果即可。
-
兄弟子树链向上连到某个祖先的链,需要处理出最长的上方链。
然后直接 dp 找到拆的位置。
对于最小值,跑出直径,然后取直径中点连接
对于最大值,跑出直径一点即可,连接两个直径即可
代码:
#include<bits/stdc++.h>
using namespace std;
int n,f[500005],d[500005][3],w[500005][2],u[500005],g[500005],ma,mi=1e9,ma1,ma2,mi1,mi2,mi3,mi4,ma3,ma4,pre[500005],dep[500005],tmp,q[500005],top;
/*
f 最长
d[0/1/2] 最长/次长链
w[0/1] 儿子子树内最长/次长
u 向上连接最长
g 拆了此点和父亲后父亲树的直径
*/
vector<int> e[500005];
void dfs(int p,int fa){
for(int i:e[p]){
if(i==fa)continue;
dfs(i,p);
f[p]=max({f[p],d[p][0]+d[i][0]+1,f[i]});
if(d[i][0]+1>d[p][0])d[p][2]=d[p][1],d[p][1]=d[p][0],d[p][0]=d[i][0]+1;
else if(d[i][0]+1>d[p][1])d[p][2]=d[p][1],d[p][1]=d[i][0]+1;
else if(d[i][0]+1>d[p][2])d[p][2]=d[i][0]+1;
if(f[i]>w[p][0])w[p][1]=w[p][0],w[p][0]=f[i];
else if(f[i]>w[p][1])w[p][1]=f[i];
}
}
void dfs2(int p,int fa){
if(fa){
int len=f[p]+g[p]+1;
if(len>ma)ma=len,ma1=fa,ma2=p;
len=max({f[p],g[p],(f[p]+1)/2+(g[p]+1)/2+1});
if(len<mi)mi=len,mi1=fa,mi2=p;
}
for(int i:e[p]){
if(i==fa)continue;
u[i]=u[p]+1;
g[i]=g[p];
if(d[p][0]==d[i][0]+1){
g[i]=max({g[i],u[p]+d[p][1],d[p][1]+d[p][2]});
u[i]=max(u[i],d[p][1]+1);
}
else if(d[p][1]==d[i][0]+1){
g[i]=max({g[i],u[p]+d[p][0],d[p][0]+d[p][2]});
u[i]=max(u[i],d[p][0]+1);
}
else {
g[i]=max({g[i],u[p]+d[p][0],d[p][0]+d[p][1]});
u[i]=max(u[i],d[p][0]+1);
}
if(f[i]==w[p][0])g[i]=max(g[i],w[p][1]);
else g[i]=max(g[i],w[p][0]);
dfs2(i,p);
}
}
void dfs3(int p,int fa,int y){
dep[p]=dep[fa]+1;
pre[p]=fa;
if(dep[p]>dep[tmp])tmp=p;
for(int i:e[p]){
if(i==fa||i==y)continue;
dfs3(i,p,y);
}
}
void getd(int x,int y){
top=tmp=0;
dfs3(x,0,y);
int w=tmp;
tmp=0;
dfs3(w,0,y);
while(tmp!=w){
q[++top]=tmp;
tmp=pre[tmp];
}
q[++top]=tmp;
}
signed main(){
cin>>n;
for(int i=1,x,y;i<n;i++){
cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
for(int i=1;i<=n;i++)reverse(e[i].begin(),e[i].end());
dfs(1,0);
dfs2(1,0);
getd(mi1,mi2),mi3=q[(top+1)/2];
getd(mi2,mi1),mi4=q[(top+1)/2];
tmp=0,dfs3(ma1,0,ma2),ma3=tmp;
tmp=0,dfs3(ma2,0,ma1),ma4=tmp;
cout<<mi<<' '<<mi1<<' '<<mi2<<' '<<mi3<<' '<<mi4<<endl;
cout<<ma<<' '<<ma1<<' '<<ma2<<' '<<ma3<<' '<<ma4<<endl;
return 0;
}

浙公网安备 33010602011771号