[NOI2003]逃学的小孩 --- 树的直径

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27121257/article/details/82011008

传送门:洛谷P4408


题目描述

Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:“喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?”一听说要考试,Chris的父母就心急如焚,他们决定在尽量短的时间内找到Chris。他们告诉Chris的老师:“根据以往的经验,Chris现在必然躲在朋友Shermie或Yashiro家里偷玩《拳皇》游戏。现在,我们就从家出发去找Chris,一但找到,我们立刻给您打电话。”说完砰的一声把电话挂了。

Chris居住的城市由N个居住点和若干条连接居住点的双向街道组成,经过街道x需花费Tx分钟。可以保证,任两个居住点间有且仅有一条通路。Chris家在点CShermie和Yashiro分别住在点A和点B。Chris的老师和Chris的父母都有城市地图,但Chris的父母知道点A、B、C的具体位置而Chris的老师不知。

为了尽快找到Chris,Chris的父母会遵守以下两条规则:

  1. 如果A距离C比B距离C近,那么Chris的父母先去Shermie家寻找Chris,如果找不到,Chris的父母再去Yashiro家;反之亦然。
  2. Chris的父母总沿着两点间唯一的通路行走。

显然,Chris的老师知道Chris的父母在寻找Chris的过程中会遵守以上两条规则,但由于他并不知道A,B,C的具体位置,所以现在他希望你告诉他,最坏情况下Chris的父母要耗费多长时间才能找到Chris?


分析

树的直径题都这么毒瘤么,题面不可读系列
可以将题目的要求拆成两部分 求 A B / C A\to B / C 最小值的最大值 和 B C B \to C 的最大值
求树上最长路径的的话,那就是树的直径了, 因此 B C B \to C 必定为树的直径.两遍dfs确定好 B B C C 点即可,
对于 A B / C A\to B / C ,可以将其拆成两部分, A P A \to P (P在树的直径上),以及 m i n ( P B , P C ) min(P \to B, P \to C) ,对此,枚举直径上的每个点,求出不经过直径其他点最长距离(即为 A P A \to P ).比较更新答案即可.


代码

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define IL inline

using namespace std;

IL int read()
{
    char c = getchar();
    int sum = 0 ,k = 1;
    for(;'0' > c || c > '9'; c = getchar())
        if(c == '-') k = -1;
    for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
    return sum * k;
}

int to[400005], nxt[400005], val[400005];
int last[200005];
int cnt;
IL void add(int u, int v, int w)
{
    to[++cnt] = v; nxt[cnt] = last[u]; val[cnt] = w; last[u] = cnt;
    to[++cnt] = u; nxt[cnt] = last[v]; val[cnt] = w; last[v] = cnt;
}

typedef long long ll;

int n, m;
ll dis[200005];
int fa[200005];

bool check[200005];
IL ll min_(ll x, ll y) { return x < y ? x : y; }
IL ll max_(ll x, ll y) { return x > y ? x : y; }

IL void dfs(int u, int &p)
{
    if(dis[u] > dis[p]) p = u;
    for(int i = last[u], v; (v = to[i]); i = nxt[i])
    if(v != fa[u])
    {
        dis[v] = dis[u] + val[i];
        fa[v] = u;
        dfs(v, p);
    }
}

IL void dfs2(int u, int pre, ll d, ll &maxd)
{
    if(d > maxd) maxd = d;
    for(int i = last[u], v; (v = to[i]); i = nxt[i])
    if(v != pre && !check[v])
        dfs2(v, u, d + val[i], maxd);
}

int main()
{
    n = read(); m = read();
    
    for(int i = 1, x, y; i <= m; ++i)
    {
    	x = read(); y = read();
    	add(x, y, read());
    }
    
    int S = 0, T = 0;
    dfs(1, T);
    dis[T] = 0; fa[T] = 0;
    dfs(T, S);
    
    for(int i = S; i; i = fa[i])
    	check[i] = 1;
    ll ans = 0, maxd;
    for(int i = S; i; i = fa[i])
    {
    	maxd = 0;
    	dfs2(i, 0, min_(dis[i], dis[S] - dis[i]), maxd);
    	ans = max_(ans, maxd);
    }
    ans += dis[S];
    printf("%lld\n", ans);
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/82011008
今日推荐