[xJOI3335] 树的直径(树上最远点)

Posted qixingzhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[xJOI3335] 树的直径(树上最远点)相关的知识,希望对你有一定的参考价值。

题目大意就是求解一棵有边权的树上,距离最远的两点间的距离。
很容易想到Floyd或是暴力搜索的算法,但是这样过不了……

介绍一种非常经典的算法:选定任意一个点u作为根节点,从u开始BFS求出距离u最大的点s,再从s点出发BFS到距离s最大的点t,则dis(s,t)即为树的直径

证明:

(一):u在直径上:由于u为根节点,所以直径必为u到两子树的最大距离之和,这个证起来很简单。

(二):u不在直径上:

  ① 走着走着走到直径上,那么同(一)

  ②与直径不相交,这种情况事实上是不存在的,可以用不等式推一下。


Code

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int N = 100010;
const int INF = 715827882;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ - && (c < 0 || c > 9)) c = getchar();
    if(c == -) w = -1, c = getchar();
    while(c >= 0 && c <= 9) x = (x << 3) +(x << 1) + c - 0, c = getchar();
    return x * w;
}
struct Edge{
    int to,cost;
    Edge(int _u, int _v): to(_u),cost(_v) {}
};
int n,m,ans,x,y,z,anss;
vector <Edge> G[N];
queue <int> q;
int vis[N],d[N];
inline void AddEdge(int u, int v, int w){
    Edge e(v,w);
    G[u].push_back(e);
}
inline void BFS(int s){
    memset(d,0,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[s] = 0;
    while(!q.empty())q.pop();
    q.push(s);
    int cur,sz,to;
    while(!q.empty()){
        cur = q.front();
        q.pop();
        if(vis[cur]) continue;
        vis[cur] = 1;
        sz = G[cur].size(),to;
        for(int i = 0; i < sz; ++i){
            to = G[cur][i].to;
            if(!vis[to]){
                d[to] = d[cur] + G[cur][i].cost;
                q.push(to);
            }
        }
    }
}
int main(){
//  freopen(".in","r",stdin);
    n = r;
    for(int i = 1; i < n; ++i){
        x=r,y=r,z=r;
        AddEdge(x,y,z);
        AddEdge(y,x,z);
    }
    BFS(1);
    int tmp,mx=0;
    for(int i = 1; i <= n; ++i){
        if(d[i] > mx){
            mx = d[i];
            tmp = i;
        }
    }
    BFS(tmp);
    mx = 0;
    for(int i = 1; i <= n; ++i){
        if(d[i] > mx){
            mx = d[i];
            tmp = i;
        }
    }
    printf("%d",d[tmp]);
    return 0;
}

 

以上是关于[xJOI3335] 树的直径(树上最远点)的主要内容,如果未能解决你的问题,请参考以下文章

[51nod] 1766树上的最远点对 树的直径 树剖LCA+ST表静态查询

[51nod] 1766树上的最远点对 树的直径 树剖LCA+ST表静态查询

树的直径求法与性质(附例题)

CS academy Growing Trees模板DP求树的直径

树的直径

Cf #292 DDrazil and Morning Exercise(树的直径,树上差分)