BZOJ1509: [NOI2003]逃学的小孩

1509: [NOI2003]逃学的小孩

这里写图片描述
Input

第一行是两个整数N(3  N 
200000)和M,分别表示居住点总数和街道总数。以下M行,每行给出一条街道的信息。第i+1行包含整数Ui、Vi、Ti(1Ui, 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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值