G 火山哥周游世界(树上走过确切k个点的最短时间,树形dp)

题:https://ac.nowcoder.com/acm/contest/4114/G

题意:给定一棵树,给定m个确定的点,问从1~n为起点开始,走过着m个点的最短距离是多少(不用回来)

分析:考虑根为1的情况,那么答案就是(所有1到m个点的边距离和)*2-(1到最远点的距离),因为不用回来;

   考虑换根,假设节点 i 到其子树的确定点的距离和的2倍为sum[i],在第一次dfs过程中我们可以算出每一个的sum[i],然后将sum[i]转义成以 i 为根到m个点的边的距离和的2倍;

   关键是考虑换根后sum[i]的父亲边的更新:先令:sum[i]=sum[fa[i]] 若 i 子树中有确定点,那么-=2*w,若父亲边有确定点,那么+=2*w;

   重要的一步是 i 到最远点距离的更新,假设更新fa->i , T节点为fa为根的最远节点;

   · 要是fa->i 不是fa->T的路径,那么 i 的最远距离即为fa的最远距离+w(i与fa的边权)

   ·否则,说明fa的最远距离给占用,那么肯定是w+x,根据贪心,这个x必须为当fa为根节点时离fa次远的距离;

   所以就需要维护最远距离fir和次远距离sec。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define MP make_pair
#define pil pair<int,ll>
const int inf=0x3f3f3f3f;
const ll INF=1e18;
const int M=5e5+5;
vector<pil >g[M];
int n,m,sz[M],nex[M];
ll fir[M],sec[M],sum[M];
void upd(ll x,int u,int v){
    if(x>=fir[u]){
        sec[u]=fir[u],fir[u]=x;
        nex[u]=v;
    }
    else
        sec[u]=max(sec[u],x);
}
void dfs1(int u,int fa){
    for(auto it:g[u]){
        int v=it.first;
        ll w=it.second;
        if(v!=fa){
            dfs1(v,u);
            sz[u]+=sz[v];
            if(sz[v]){
                sum[u]+=sum[v]+2ll*w;
                upd(fir[v]+w*(sz[v]!=0),u,v);
            }

        }
    }
}
void dfs2(int u,int fa){
    for(auto it:g[u]){
        int v=it.first;
        ll w=it.second;
        if(v!=fa){
            sum[v]=sum[u]-2ll*w*(sz[v]!=0)+2ll*w*(m-sz[v]!=0);
            if(sz[v]!=m){
                if(v==nex[u])
                    upd(sec[u]+w,v,0);
                else
                    upd(fir[u]+w,v,0);
            }

            dfs2(v,u);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        int u,v;
        ll w;
        scanf("%d%d%lld",&u,&v,&w);
        g[u].pb(MP(v,w));
        g[v].pb(MP(u,w));
    }
    for(int x,i=1;i<=m;i++){
        scanf("%d",&x);
        sz[x]=1;
    }
    dfs1(1,0);

    dfs2(1,0);

    for(int i=1;i<=n;i++)
        printf("%lld
",sum[i]-fir[i]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/13611226.html