传送门
这是一道很有意思的题。
我们把所有的关键点都提出来,当成一棵有边权的虚树。
然后发现虚树上除最后不回到虚根的那条路径外外每条边都会被走两遍。
显然要让答案最优,不走的路径应该在虚树的直径上,于是我们dfs出虚树的直径。
注意对于不在虚树上的节点花费还需要多加dis(i,虚树)∗2dis(i,虚树)*2dis(i,虚树)∗2。
代码:
#include<bits/stdc++.h>
#define N 500005
#define ll long long
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,k,first[N],siz[N],rt,cnt=0;
bool is[N];
ll d1[N],d2[N],sum=0;
struct edge{int v,next;ll w;}e[N<<1];
inline void add(int u,int v,ll w){e[++cnt].v=v,e[cnt].w=w,e[cnt].next=first[u],first[u]=cnt;}
inline void dfs1(int p,int fa){
siz[p]=is[p];
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v==fa)continue;
d1[v]=d1[p]+e[i].w;
if(is[v]&&d1[v]>d1[rt])rt=v;
dfs1(v,p);
if(siz[v])sum+=e[i].w;
siz[p]+=siz[v];
}
is[p]=(siz[p]!=0);
}
inline void dfs2(int p,int fa){
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v==fa)continue;
d1[v]=d1[p]+e[i].w;
if(is[v]&&d1[v]>d1[rt])rt=v;
dfs2(v,p);
}
}
inline void dfs3(int p,int fa){
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v==fa)continue;
d2[v]=d2[p]+e[i].w;
if(is[v]&&d2[v]>d2[rt])rt=v;
dfs3(v,p);
}
}
inline void dfs4(int p,int fa){
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v==fa)continue;
d2[v]=(is[v]?0:d2[p]+e[i].w),dfs4(v,p);
}
}
int main(){
n=read(),k=read();
for(int i=1;i<n;++i){
int x=read(),y=read();
ll z=read();
add(x,y,z),add(y,x,z);
}
for(int i=1;i<=k;++i)is[rt=read()]=1;
dfs1(rt,0),memset(d1,0,sizeof(d1)),dfs2(rt,0),dfs3(rt,0);
for(int i=1;i<=n;++i)d1[i]=max(d1[i],d2[i]);
memset(d2,0,sizeof(d2)),dfs4(rt,0);
for(int i=1;i<=n;++i)printf("%lld\n",sum*2+d2[i]*2-d1[i]);
return 0;
}