一本通1581旅游规划

1581:旅游规划

时间限制: 1000 ms         内存限制: 524288 KB

描述
W市的交通规划出现了重大问题,市*下决心在全市的各大交通路口安排交通疏导员来疏导密集的车流。但由于人员不足,W市市长决定只在最需要安排人员的路口安放人员。具体说来,W市的交通网络十分简单,它包括n个交叉路口和n-1条街道,任意一条街道连接两个交叉路口,并且任意两个交叉路口之间都存在一条路径互相连接。经过长期调查结果显示如果一个交叉路口位于W市交通网的最长路径上,那么这个路口必然拥挤不堪,所谓最长路径定义为某条路径p=(v1,v2,v3…vk),路径经过的路口各不相同且城市中不存在长度>k的路径(因此可能存在着不唯一的最长路径)。因此W市市长希望知道有哪些路口位于城市交通网的最长路径之上。

格式
输入格式
第一行包括一个整数n。

之后的n-1行每行包括两个整数u, v表示编号为u和v的路口之间存在着一条街道(注意:路口被依次编号为0到n-1)

输出格式
输出包括若干行,每行包括一个整数——某个位于最长路上路口的编号。

为了确保解唯一,我们规定位于所有最长路上的路口按编号顺序从小到大输出。

样例1
样例输入1
10
0 1
0 2
0 4
0 6
0 7
1 3
2 5
4 8
6 9
样例输出1
0
1
2
3
4
5
6
8
9
提示
这里存在着若干条最长路径,其中的两条是3-1-0-2-5与8-4-0-6-9,他们的长度都是5,但是不存在长度>5的路径且所有最长路径都不包括路口7,所以答案中没有7。

数据范围:
对于50%的数据保证n<=1000
对于100%的数据保证n<=200000

 

先附上手绘的样例图(过于丑陋) 

一本通1581旅游规划

 

 

sol:一开始想求出直径的两个端点然后差分搞一下,然后发现非常wei,然后就想到如果一点在直径上,那么他不是只有两个方向延伸吗?(向儿子,或者向上爬几步爬到根或者爬到别的子树里去);所以两遍dfs就可以求出两个方向的最长值,还有注意下因为Up[x]=max(Up[fa]+1,Down[fa]+1),但是如果Down[fa]最大值就是x转移过来的话,要用Down[fa]的次大值来转移,所以Down要记录Zd和Cd

一本通1581旅游规划
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
    int s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-');
        ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48);
        ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(int x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');
        return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
inline void writeln(int x)
{
    write(x);
    putchar('\n');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) writeln(x)
const int N=200005,M=400005;
int n;
struct Tree
{
    int tot,Next[M],to[M],head[N];
    inline void add(int x,int y)
    {
        Next[++tot]=head[x];
        to[tot]=y;
        head[x]=tot;
        return;
    }
    int Down_Zd[N],From_Zd[N],Down_Cd[N],From_Cd[N];
    inline void dfs_Down(int x,int fa)
    {
        int i;
        for(i=head[x];i;i=Next[i]) if(to[i]!=fa)
        {
            dfs_Down(to[i],x);
            if(Down_Zd[to[i]]+1>Down_Zd[x])
            {
                From_Cd[x]=From_Zd[x];
                Down_Cd[x]=Down_Zd[x];
                From_Zd[x]=to[i];
                Down_Zd[x]=Down_Zd[to[i]]+1;
            }
            else if(Down_Zd[to[i]]+1>Down_Cd[x])
            {
                From_Cd[x]=to[i];
                Down_Cd[x]=Down_Zd[to[i]]+1;
            }
        }
        return;
    }
    int Up[N];
    inline void dfs_Up(int x,int fa)
    {
        if(fa)
        {
            if(From_Zd[fa]!=x) Up[x]=max(Up[fa]+1,Down_Zd[fa]+1);
            else Up[x]=max(Up[fa]+1,Down_Cd[fa]+1);
        }
        int i;
        for(i=head[x];i;i=Next[i]) if(to[i]!=fa)
        {
            dfs_Up(to[i],x);
        }
        return;
    }
    inline void Output()
    {
        int i,ans=0;
        for(i=1;i<=n;i++) ans=max(ans,(Down_Zd[i]+Up[i],Down_Zd[i]+Down_Cd[i]));
        for(i=1;i<=n;i++)
        {
//            printf("@ %d %d\n",Down_Zd[i],Up[i]);
            if((Down_Zd[i]+Up[i]==ans)||(Down_Zd[i]+Down_Cd[i]==ans)) Wl(i-1);
        }
        return;
    }
    inline void Init()
    {
        tot=0;
        memset(head,0,sizeof head);
        return;
    }
}T;
int main()
{
    int i;
    T.Init();
    R(n);
    for(i=1;i<n;i++)
    {
        int x,y;
        x=read()+1; y=read()+1;
        T.add(x,y); T.add(y,x);
    }
    T.dfs_Down(1,0);
    T.dfs_Up(1,0);
    T.Output();
    return 0;
}
/*
input
10
0 1
0 2
0 4
0 6
0 7
1 3
2 5
4 8
6 9
output
0
1
2
3
4
5
6
7
8
9
*/
View Code

 

上一篇:Oracle及PL SQL常用功能


下一篇:使用MySQL Shell创建MGR