牛子练习赛93 C

点权

题目链接
看完题就知道是换根dp了,哭哭。
就是分两次dfs,
第一次dfs 用儿子节点更新父亲节点
第二次dfs 用父亲节点更新儿子节点
然后这题需要维护最短路/次短路/次次短路

然后,我的wa点在哪里呢?
第二次dfs的时候,当我们用父亲更新儿子的时候,相当于从父亲过来的路径也是当作儿子的一条路径 且 更新——儿子的(最短路 次短路 次次短路)

#include <bits/stdc++.h>

using  namespace  std;

typedef long long ll;
#define int ll
#define pb push_back
#define is insert
#define PII pair<int,int>
//mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
//ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}


const int N=1e5+50;
const ll INF=0x3f3f3f3f;
const ll MOD=1e9+7;

int n,m;
int d[N];

int head[N];
struct node {
    int to,nxt;
    ll val;
}e[N<<1];
int idx=0;
void add_edge(int u,int v,ll val){
    e[idx]={v,head[u],val};
    head[u]=idx++;
}
ll d1[N],d2[N],d3[N];//从以i为根的子树转移上来的最短路 次短路 次次短路
ll p1[N],p2[N];//p1[i]表示 以i为根的子树最短路走到的第一个点
ll rt=1;
ll up[N];
ll dfs_d(int u,int pre){
    for(int i=head[u];i!=-1;i=e[i].nxt){
        ll v=e[i].to,val=e[i].val;
        if(v==pre)continue;
        ll d=dfs_d(v,u)+val;
        if(d>=INF)continue;
        if(d<=d1[u]){
            d3[u]=d2[u],d2[u]=d1[u],d1[u]=d;
            p2[u]=p1[u],p1[u]=v;
        }
        else if(d<=d2[u]){
            d3[u]=d2[u];d2[u]=d;p2[u]=v;
        }
        else if(d<d3[u]){
            d3[u]=d;
        }
    }
    if(d[u]==1){
        d1[u]=0,d2[u]=0,d3[u]=0;
    }
    if(d2[u]==INF){
        return INF;
    }
    return d1[u]+d2[u];
}
void dfs_u(int u,int pre){
    for(int i=head[u];i!=-1;i=e[i].nxt){
        ll v=e[i].to,val=e[i].val;
        if(v==pre)continue;
        ll d;
        if(p1[u]==v){
            d=d2[u]+d3[u]+val;
        }
        else if(p2[u]==v){
            d=d1[u]+d3[u]+val;
        }
        else {
            d=d1[u]+d2[u]+val;
        }
        if(d<=d1[v]){
            d3[v]=d2[v];d2[v]=d1[v];d1[v]=d;
            p2[v]=p1[v];p1[v]=u;
        }
        else if(d<=d2[v]){
            d3[v]=d2[v];d2[v]=d;
            p2[v]=u;
        }
        else if(d<d3[v]){
            d3[v]=d;
        }
        up[v]=min(up[v],d1[v]+d2[v]);
        dfs_u(v,u);
    }
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++){
        d1[i]=d2[i]=d3[i]=INF;
        head[i]=-1;
    }
    for(int i=1;i<n;i++){
        ll u,v,val;cin>>u>>v>>val;
        add_edge(u,v,val);
        add_edge(v,u,val);
        d[u]++;d[v]++;
    }
    if(n==1){
        cout<<0;
        return ;
    }
    for(int i=1;i<=n;i++){
        if(d[i]>1){
            rt=i;
            break;
        }
    }
    dfs_d(rt,-1);
    for(int i=1;i<=n;i++){
        up[i]=d1[i]+d2[i];
        if(up[i]>=INF)up[i]=INF;
    }
    dfs_u(rt,-1);
    for(int i=1;i<=n;i++){
//        cout<<up[i]<<" ";
        if(up[i]<=INF/2)cout<<up[i]<<" ";
        else {
            cout<<-1<<" ";
        }
    }
}
signed main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int __=1;//cin>>__;
    while(__--){
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值