BZOJ1509: [NOI2003]逃学的小孩
1509: [NOI2003]逃学的小孩
Input第一行是两个整数N(3 N
200000)和M,分别表示居住点总数和街道总数。下面M行,每行给出一条街道的信息。
第i+1行包括整数Ui、Vi、Ti(1Ui, Vi
N。1 Ti 1000000000),表示街道i连接居住点Ui和Vi,而且经过街道i需花费Ti分钟。街道信息不会反复给出。Output
仅包括整数T。即最坏情况下Chris的父母须要花费T分钟才干找到Chris。
Sample Input
4 3
1 2 1
2 3 1
3 4 1
Sample Output
4
题解:
依照题意理解,找出3条路径a,b,c.(a>b>c)
答案就是(a+2*b+c)
树形dp,两次dfs
先以儿子dp。找出最大。中间,最小。
可是父亲所在的链也是一条链。所以须要第二次dfs,推断父亲所在的链。
代码:
/**************************************************************
Problem: 1509
User: wjyi
Language: C++
Result: Accepted
Time:1188 ms
Memory:13208 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=200005;
struct Node{
int to,next,w;
}e[maxn<<1];
int tot,head[maxn],n,m;
ll mx1[maxn],mx2[maxn],mx3[maxn],f[maxn],ans;
bool vis[maxn];
void add(int u,int v,int w){
e[++tot]=(Node){v,head[u],w};head[u]=tot;
}
void dfs(int x){
vis[x]=1;mx1[x]=mx2[x]=0;
for(int i=head[x];i;i=e[i].next)if(!vis[e[i].to]){
dfs(e[i].to);
mx3[x]=max(mx3[x],mx1[e[i].to]+e[i].w);
if(mx3[x]>mx2[x])swap(mx3[x],mx2[x]);
if(mx2[x]>mx1[x])swap(mx1[x],mx2[x]);
}
}
void dfs1(int x){
vis[x]=1;
for(int i=head[x];i;i=e[i].next)
if(!vis[e[i].to]){
f[e[i].to]=f[x]+e[i].w;
if(mx1[e[i].to]+e[i].w==mx1[x])
f[e[i].to]=max(f[e[i].to],mx2[x]+e[i].w);
else
f[e[i].to]=max(f[e[i].to],mx1[x]+e[i].w);
dfs1(e[i].to);
}
}
void update(ll &x,ll &y,ll &z){
if(y>x)swap(x,y);
if(z>x)swap(x,z);
if(z>y)swap(y,z);
ans=max(ans,x+(y<<1)+z);
}
int main(){
scanf("%d%d",&n,&m);
int u,v,w;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
memset(vis,0,sizeof(vis));
dfs(1);
memset(vis,0,sizeof(vis));
dfs1(1);
ans=0;
for(int i=1;i<=n;i++)
f[i]<=mx3[i]?update(mx1[i],mx2[i],mx3[i]):update(mx1[i],mx2[i],f[i]);
printf("%lld\n",ans);
return 0;
}