[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的父母會遵守以下兩條規則:
- 如果A距離C比B距離C近,那麽Chris的父母先去Shermie家尋找Chris,如果找不到,Chris的父母再去Yashiro家;反之亦然。
- 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。
此題很容易看出是要先求樹的直徑,然後的操作我一開始的思路有些錯誤。
一開始我的想法是在直徑上找一個點作為起點,在dfs的過程中記錄下直徑的路徑和權值road,
把road數組前綴和化,於是答案就是lenth+max{min(lenth-road[i],road[i])};
但是在WA掉以後,我發現起點不在直徑上也許會更好,於是我們用SPFA求出,每個點到直徑兩端的距離
那麽答案就是lenth+max{min(dis[0][i],dis[1][i])};
實現如下:
#include <algorithm> #include <iostream> #include <cmath> #include <cstring> #include <map> #include <string> #include <vector> #include <queue> #include <stack> #include <cstdio> #include <cstdlib> using namespace std; typedef long long ll; inline ll read() { register ll p(1),a(0);register char ch=getchar(); while((ch<‘0‘||ch>‘9‘)&&ch!=‘-‘) ch=getchar(); if(ch==‘-‘) p=-1,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) a=a*10+ch-48,ch=getchar(); return a*p; } const int N=200010; int n,m,u,v,head[N],cnt=0,zq,zz,len=0,book[N]; ll ans=0,w,maxn=0,road[N],dis[2][N]; struct EDGE{int nxt,to;ll val;}e[N<<1]; void add(int u,int v,ll w){e[++cnt]=(EDGE){head[u],v,w};head[u]=cnt;} void dfs(int u,int fa,ll siz) { if(siz>maxn){maxn=siz;zq=u;} for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(fa!=v) dfs(v,u,siz+e[i].val); } queue<int> Q; void SPFA(int u,int pre) { memset(dis[pre],0x3f,sizeof(dis[pre])); memset(book,0,sizeof(book)); Q.push(u);dis[pre][u]=0;book[u]=1; while(!Q.empty()) { u=Q.front();Q.pop();book[u]=0; for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(dis[pre][v]>dis[pre][u]+e[i].val) { dis[pre][v]=dis[pre][u]+e[i].val; if(!book[v]) Q.push(v); } } } int main() { // freopen("input","r",stdin); // freopen("output","w",stdout); n=read(),m=read(); for(int i=1;i<=m;i++) { u=read(),v=read(),w=read(); add(u,v,w);add(v,u,w); } dfs(1,-1,0);zz=zq,maxn=0; dfs(zq,-1,0); SPFA(zz,0);SPFA(zq,1); for(int i=1;i<=n;i++) ans=max(ans,min(dis[0][i],dis[1][i])); printf("%lld\n",ans+maxn); return 0; }
[NOI2003]逃學的小孩