2020 CCPC-Wannafly Winter Camp Day3 G 火山哥周游世界(树形dp)

题目链接
参考了大佬的做法,学到了树的中心求法。
大佬题解

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+1;
typedef long long ll;
struct node{
    int y,len,next;
}a[maxn<<1];
int n,k,head[maxn<<1],cnt=0,vis[maxn]={0},t;
ll size[maxn];//以1为根时,子树含有的国家数量
ll max1[maxn];//以1为根时,子树到国家的最长路径
ll max2[maxn];//以1为根时,子树到国家的次长路径
ll sum[maxn];//以1为根时,子树到国家的路径总和
ll num[maxn];//路径最长的那个子树节点
ll father[maxn];//通过父亲节点能到达的国家的最长路径
ll ans[maxn];//答案 
void add(int x,int y,int z)
{
    a[cnt].y=y;a[cnt].len=z;a[cnt].next=head[x];head[x]=cnt++;
}
void dfs1(int u,int fa) 
{
    if(vis[u]) size[u]=1;
    for(int i=head[u];i!=-1;i=a[i].next)
    {
        int v=a[i].y,w=a[i].len;
        if(v==fa) continue;
        dfs1(v,u);
        size[u]+=size[v];
        sum[u]+=sum[v];
        if(size[v])
        {
            sum[u]+=2*w;
            if(max1[v]+w>max1[u])
            {
                max2[u]=max1[u];
                max1[u]=max1[v]+w;
                num[u]=v;
            }
            else max2[u]=max(max2[u],max1[v]+w);
         }
    }
}
void dfs2(int u,int fa)
{
    for(int i=head[u];i!=-1;i=a[i].next)
    {
        int v=a[i].y,w=a[i].len;
        if(v==fa) continue;
        if(k-size[v]) father[v]=max(father[u],(num[u]==v)?max2[u]:max1[u])+w;//树的中心求法 
        ans[v]=ans[u];
        if(size[v])  ans[v]-=2*w;
        if(k-size[v]) ans[v]+=2*w;
        dfs2(v,u);
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d %d",&n,&k);
    for(int i=1;i<n;++i)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    for(int i=1;i<=k;++i)
    {
        scanf("%d",&t);
        vis[t]=1;
    }
    dfs1(1,0);
    ans[1]=sum[1];
    dfs2(1,0);
    for(int i=1;i<=n;++i) printf("%lld\n",ans[i]-max(father[i],max1[i]));
 }
发布了70 篇原创文章 · 获赞 0 · 访问量 2450

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104138016