旅游规划-树的直径
Description
W市的交通规划出现了重大问题,市政府下决心在全市的各大交通路口安排交通疏导员来疏导密集的车流。但由于人员不足,W市市长决定只在最需要安排人员的路口安放人员。具体说来,W市的交通网络十分简单,它包括n个交叉路口和n-1条街道,任意一条街道连接两个交叉路口,并且任意两个交叉路口之间都存在一条路径互相连接。经过长期调查结果显示如果一个交叉路口位于W市交通网的最长路径上,那么这个路口必然拥挤不堪,所谓最长路径定义为某条路径p=(v1,v2,v3…vk),路径经过的路口各不相同且城市中不存在长度>k的路径(因此可能存在着不唯一的最长路径)。因此W市市长希望知道有哪些路口位于城市交通网的最长路径之上。
Input
第一行包括一个整数n。
之后的n-1行每行包括两个整数u, v表示编号为u和v的路口之间存在着一条街道(注意:路口被依次编号为0到n-1)
Output
输出包括若干行,每行包括一个整数——某个位于最长路上路口的编号。
为了确保解唯一,我们规定位于所有最长路上的路口按编号顺序从小到大输出。
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
Hint
【样例解释】
这里存在着若干条最长路径,其中的两条是3-1-0-2-5与8-4-0-6-9,他们的长度都是5,但是不存在长度>5的路径且所有最长路径都不包括路口7,所以答案中没有7。
【数据范围】
对于50%的数据保证n<=1000
对于100%的数据保证n<=200000
思路
- dfslen求树的直径 讲解+模板
- dfs 输出直径上的点
代码
#include <iostream>
#include <cstdio>
#define maxn 200005
using namespace std;
int head[maxn],cnt,f1[maxn],f2[maxn],ans,flag[maxn];
struct fdfdfd{int next,to;}e[maxn<<1];
void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
void dfslen(int x,int pre)
{
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==pre) continue;
dfslen(v,x);
if(f1[x]<f1[v]+1) f2[x]=f1[x],f1[x]=f1[v]+1;
else if(f2[x]<f1[v]+1) f2[x]=f1[v]+1;
}
ans=max(ans,f1[x]+f2[x]);
}
void work(int x,int pre,int len)
{
if(!flag[x]) flag[x]=1;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==pre) continue;
if(f1[v]==len-1) work(v,x,len-1);
}
}
void dfs(int x,int pre)
{
if(f1[x]+f2[x]==ans) work(x,pre,f1[x]),work(x,pre,f2[x]);
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v!=pre) dfs(v,x);
}
}
int main()
{
int n; scanf("%d",&n);
for(int i=1,u,v;i<n;++i) scanf("%d%d",&u,&v),++u,++v,addedge(u,v),addedge(v,u);
dfslen(1,0); dfs(1,0);
for(int i=1;i<=n;++i){if(flag[i]) printf("%d\n",i-1);}
return 0;
}