[NOI2003]逃學的小孩 --- 樹的直徑
阿新 • • 發佈:2018-11-10
傳送門:洛谷P4408
題目描述
Chris家的電話鈴響起了,裡面傳出了Chris的老師焦急的聲音:“喂,是Chris的家長嗎?你們的孩子又沒來上課,不想參加考試了嗎?”一聽說要考試,Chris的父母就心急如焚,他們決定在儘量短的時間內找到Chris。他們告訴Chris的老師:“根據以往的經驗,Chris現在必然躲在朋友Shermie或Yashiro家裡偷玩《拳皇》遊戲。現在,我們就從家出發去找Chris,一但找到,我們立刻給您打電話。”說完砰的一聲把電話掛了。
Chris居住的城市由N個居住點和若干條連線居住點的雙向街道組成,經過街道x需花費Tx分鐘。可以保證,任兩個居住點間有且僅有一條通路。Chris家在點C
為了儘快找到Chris,Chris的父母會遵守以下兩條規則:
- 如果A距離C比B距離C近,那麼Chris的父母先去Shermie家尋找Chris,如果找不到,Chris的父母再去Yashiro家;反之亦然。
- Chris的父母總沿著兩點間唯一的通路行走。
顯然,Chris的老師知道Chris的父母在尋找Chris的過程中會遵守以上兩條規則,但由於他並不知道A,B,C的具體位置,所以現在他希望你告訴他,最壞情況下Chris的父母要耗費多長時間才能找到Chris?
分析
樹的直徑題都這麼毒瘤麼,題面不可讀系列
可以將題目的要求拆成兩部分 求
最小值的最大值 和
的最大值
求樹上最長路徑的的話,那就是樹的直徑了, 因此
必定為樹的直徑.兩遍dfs確定好
與
點即可,
對於
,可以將其拆成兩部分,
(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;
}