1. 程式人生 > >[NOI2003]逃學的小孩(樹的直徑)

[NOI2003]逃學的小孩(樹的直徑)

name namespace 要花 sin node getchar() min add 輸入輸出

[NOI2003]逃學的小孩

題目描述

Chris家的電話鈴響起了,裏面傳出了Chris的老師焦急的聲音:“餵,是Chris的家長嗎?你們的孩子又沒來上課,不想參加考試了嗎?”一聽說要考試,Chris的父母就心急如焚,他們決定在盡量短的時間內找到Chris。他們告訴Chris的老師:“根據以往的經驗,Chris現在必然躲在朋友Shermie或Yashiro家裏偷玩《拳皇》遊戲。現在,我們就從家出發去找Chris,一但找到,我們立刻給您打電話。”說完砰的一聲把電話掛了。

Chris居住的城市由N個居住點和若幹條連接居住點的雙向街道組成,經過街道x需花費Tx分鐘。可以保證,任兩個居住點間有且僅有一條通路。Chris家在點C,Shermie和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?

輸入輸出格式

輸入格式:

輸入文件第一行是兩個整數N(3 ≤ N ≤ 200000)和M,分別表示居住點總數和街道總數。

以下M行,每行給出一條街道的信息。第i+1行包含整數Ui、Vi、Ti(1≤Ui, Vi ≤ N,1 ≤ Ti ≤ 1000000000),表示街道i連接居住點Ui和Vi,並且經過街道i需花費Ti分鐘。街道信息不會重復給出。

輸出格式:

輸出文件僅包含整數T,即最壞情況下Chris的父母需要花費T分鐘才能找到Chris。

輸入輸出樣例

輸入樣例#1: 復制

4 3
1 2 1
2 3 1
3 4 1

輸出樣例#1: 復制

4



題解


數據太水了?
雖然A了,但是我的代碼是錯誤的,巨佬自行修改一下(懶得改了)。
求出樹直徑的起點和終點。
處理出每個點對於起點和終點的兩個距離。
然後掃一遍求出直徑上的點求出較短半徑即可。




代碼


#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int N=200001;
struct node{
    int nex,to;
    ll v;
}e[N];
ll n,m,root,ans,maxx;
ll dis[N],num,head[N];
ll disr[N],s,t;
ll read(){
    ll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void add(int from,int to,ll v){
    num++;
    e[num].to=to;
    e[num].v=v;
    e[num].nex=head[from];
    head[from]=num;
}

void dfs(int x,int fa){
    for(int i=head[x];i;i=e[i].nex){
        int v=e[i].to;if(v==fa)continue;
        dis[v]=dis[x]+e[i].v;dfs(v,x);
    }
}

void dfs2(int x,int fa){
    for(int i=head[x];i;i=e[i].nex){
        int v=e[i].to;if(v==fa)continue ;
        disr[v]=disr[x]+e[i].v;dfs2(v,x);
    }
}

int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        add(x,y,z);add(y,x,z);
    }
    dfs(1,1);
    for(int i=1;i<=n;i++)
    {if(dis[i]>maxx)s=i,maxx=dis[i];dis[i]=0;}
    dfs(s,0);maxx=0;
    for(int i=1;i<=n;i++)
    if(dis[i]>maxx)t=i,maxx=dis[i];
    dfs2(t,0);
    for(int i=1;i<=n;i++)
    if(i!=s&&i!=t)
    ans=max(ans,min(dis[i],disr[i]));
    printf("%lld\n",ans+maxx);
    return 0;
}

[NOI2003]逃學的小孩(樹的直徑)