我们设计状态

g[i][j]表示当前在i节点,处理到了第k棵子树时,还能向外扩展j层的最小花费。

f[i][j]表示当前在i节点,处理到了第k棵子树时,在i节点的子树中向下还有j层没有被覆盖时的最小花费。

那么状态转移(现在在点u,v为新子树):

g[u][j]=min(g[u][j]+f[v][j],g[v][j+1]+f[u][i+1])

意思分别是:

u点向上还要覆盖j层的话,也就是原来就可以向上覆盖j层,加上这棵新的子树的花费

u点向上还要覆盖j层的话,也就是这棵新子树可以向上覆盖j+1层,加上原来子树的花费

那么代码如下:

#include<bits/stdc++.h>
#define N 500007
#define inf 0x3f3f3f3f
using namespace std;
int n,m,dis,cnt;
int val[N],head[N],f[N][21],g[N][21];
bool vis[N];
struct Edge
{
    int to,nxt;
}edge[N<<1];
void Add(int u,int v)
{
    edge[++cnt]=(Edge){v,head[u]};
    head[u]=cnt;
}
void Dfs(int u,int fa)
{
    if(vis[u])
        f[u][0]=g[u][0]=val[u];
    for(int i=1;i<=dis;++i)
        g[u][i]=val[u];
    g[u][dis+1]=inf;
    for(int i=head[u];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==fa)
            continue;
        Dfs(v,u);
        for(int j=0;j<=dis;++j)
            g[u][j]=min(g[u][j]+f[v][j],g[v][j+1]+f[u][j+1]);
        for(int j=dis;j>=0;--j)
            g[u][j]=min(g[u][j],g[u][j+1]);
        f[u][0]=g[u][0];
        for(int j=1;j<=dis+1;++j)
            f[u][j]+=f[v][j-1];
        for(int j=1;j<=dis+1;++j)
            f[u][j]=min(f[u][j],f[u][j-1]);
    }
}
int main()
{
    scanf("%d%d",&n,&dis);
    for(int i=1;i<=n;++i)
        scanf("%d",&val[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    {
        int in;
        scanf("%d",&in);
        vis[in]=true;
    }      
    for(int i=1;i<n;++i)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        Add(u,v);
        Add(v,u);
    }
    Dfs(1,0);
    printf("%d",f[1][0]);
    return 0;
}