因为要求每个点为根的答案,显然会想到换根 D P DP DP(虽然不一定
我们首先先申明几个变量:
f u f_u fu表示把 u u u子树内的任务做完并且回到 u u u点的花费
g u g_u gu表示 u u u子树外的花费
d i s u , 0 / 1 dis_{u,0/1} disu,0/1表示 u u u子树内的最长链/次长链
u p u up_u upu表示 u u u子树外的最长链
那么对于每个点的贡献 a n s i = f i + g i − max ( u p i , d i s i , 0 ) ans_i=f_i+g_i-\max(up_i,dis_{i,0}) ansi=fi+gi−max(upi,disi,0)。这个如何理解:就是子树内的要加子树外的也要加,我们可以选择一个位置 v v v为结束点,此刻我们就不用回溯至子树根节点了。按照贪心我们选择对答案贡献最大的点。
f u f_u fu很好求,即 f u = ∑ v ∈ u f v + ( 2 × w u , v ) f_u=\sum_{v∈u}f_v+(2\times w_{u,v}) fu=∑v∈ufv+(2×wu,v)。这个就不多讲了。
g v g_v gv稍微想想可以理解即 g v = g u + ( f u − f v ) g_v=g_u+(f_u-f_v) gv=gu+(fu−fv) 这个如何理解:就是这个 g v g_v gv包含了 u u u外的子树(这个贡献即为 g u g_u gu)以及同属于 u u u子树但不为 v v v的另外子树(这个贡献即为 f u − f v f_u-f_v fu−fv)
u p v up_v upv分两种情况:一种为其父节点 u u u的最长链上的点,以及不为最长链上的点。这个也很好转移
d i s u , 0 / 1 dis_{u,0/1} disu,0/1在预处理中就可以处理好。
以及要考虑一种情况即 v ∈ u v∈u v∈u没有关键点,那么 g v g_v gv要加上 2 × w u , v 2\times w_{u,v} 2×wu,v
时间复杂度 O ( n ) O(n) O(n)
#include
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
#define int long long
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int mod=1e9+7;
const int mo=998244353;
const int N=5e5+5;
int n,m,cnt,head[N],f[N],g[N];
int dis[N][2],a[N],up[N],siz[N],ans;
struct Node
{
int nex,to,w;
};
Node e[N<<1];
inline void jia(int u,int v,int w)
{
e[++cnt].nex=head[u];
head[u]=cnt;
e[cnt].to=v;
e[cnt].w=w;
}
inline void dfs(int u,int fa)
{
siz[u]=a[u];
GO(i,u)
{
int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
if(siz[v])
{
f[u]+=(f[v]+2*e[i].w);
if(dis[u][0]<dis[v][0]+e[i].w)
dis[u][1]=dis[u][0],dis[u][0]=dis[v][0]+e[i].w;
else if(dis[u][1]<dis[v][0]+e[i].w) dis[u][1]=dis[v][0]+e[i].w;
}
}
}
inline void dp(int u,int fa)
{
GO(i,u)
{
int v=e[i].to;
if(v==fa) continue;
if(m-siz[v])
{
g[v]=g[u]+(f[u]-f[v]);
if(!siz[v]) g[v]+=2*e[i].w;
if(dis[v][0]+e[i].w==dis[u][0])
up[v]=max(up[u],dis[u][1])+e[i].w;
else up[v]=max(up[u],dis[u][0])+e[i].w;
}
dp(v,u);
}
}
signed main()
{
n=read();m=read();
For(i,1,n-1)
{
int x,y,w;
x=read(),y=read(),w=read();
jia(x,y,w);
jia(y,x,w);
}
For(i,1,m) a[read()]++;
dfs(1,0);
dp(1,0);
For(i,1,n) printf("%lld\n",f[i]+g[i]-max(up[i],dis[i][0]));
return 0;
}