【题解】1581:旅游规划
\(Description:\)
给出一棵树,求树上位于最长路径上的点,即位于与直径长度相同的路径上的所有点
\(Sample\) \(Input:\)
10
0 1
0 2
0 4
0 6
0 7
1 3
2 5
4 8
6 9
\(Sample\) \(Output:\)
0
1
2
3
4
5
6
8
9
\(Solution:\)
震惊一本通上居然有这么好的题,这题求直径很简单,但是怎么求位于直径上的点?
考虑再dp一遍,求出一个点到除他所在的子树的最大距离。
然后枚举所有点看看是不是字树内的最大距离加上子树外的最大距离等于直径长度。
怎么求子树外的最大距离呢?
其实只要从上到下,从根到叶子结点转移。
设当前点为 \(u\) ,他的儿子 \(v\) ,\(f[v]\) 表示 \(v\) 子树外的最远距离。
那么如果这个点吧 \(d1[u]\) 更新了,那么他就不能从 \(d1[u]\) 哪里得到更新
不然就可以。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,cnt,Max_dis;
const int N=2e5+5;
int d1[N],d2[N],pre[N],nxt[N],ans[N];
int f[N];
bool vis[N];
vector <int> E[N];
inline void dfs1(int u,int fa){
for(int i=0;i<(int)E[u].size();++i){
int v=E[u][i];
if(v==fa) continue;
dfs1(v,u);
if(d1[v]+1>d1[u]){
d2[u]=d1[u];
d1[u]=d1[v]+1;
}
else if(d1[v]+1>d2[u])
d2[u]=d1[v]+1;
}
Max_dis=max(Max_dis,d1[u]+d2[u]);
}
inline void dfs2(int u,int fa){
int num=0;
for(int i=0;i<(int)E[u].size();++i){
int v=E[u][i];
if(v==fa) continue;
if(d1[u]==d1[v]+1) num++;
}
for(int i=0;i<(int)E[u].size();++i){
int v=E[u][i];
if(v==fa) continue;
if(d1[u]!=d1[v]+1 || (num>1 && d1[u]==d1[v]+1)) f[v]=max(f[u],d1[u])+1;
else f[v]=max(f[u],d2[u])+1;
dfs2(v,u);
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n-1;++i){
int u=0,v=0;
scanf("%d%d",&u,&v);
E[u].push_back(v);
E[v].push_back(u);
}
dfs1(0,0);
dfs2(0,0);
for(int i=0;i<n;++i)
if(d1[i]+max(d2[i],f[i])==Max_dis)
printf("%d\n",i);
return 0;
}