SOL
树形DP
f[i][j]表示i的子树中,最高覆盖到i向下第j层的最小花费。
g[i][j]表示i的子树全部覆盖,还能向上覆盖j层的最小花费。
#pragma GCC optimize("-O2") #include<bits/stdc++.h> #define sight(c) (‘0‘<=c&&c<=‘9‘) #define eho(x) for(int i=head[x];i;i=net[i]) #define min(a,b) (a)<(b)?(a):(b) #define DEP 23 #define inf (1<<26) #define N 500007 int f[N][DEP],g[N][DEP],head[N],fall[N<<1],net[N<<1],w[N],d,tot,n,m,X,A,B; bool u[N]; void dfs(int x,int fa){ if (u[x]) f[x][0]=g[x][0]=w[x]; for (int i=1;i<=d;i++) f[x][i]=w[x]; f[x][d+1]=inf; eho(x) if (fall[i]^fa) { dfs(fall[i],x); for (int j=d;~j;j--) f[x][j]=min(f[x][j]+g[fall[i]][j],g[x][j+1]+f[fall[i]][j+1]); for (int j=d;~j;j--) f[x][j]=min(f[x][j],f[x][j+1]); g[x][0]=f[x][0]; for (int j=1;j<=d;j++) g[x][j]+=g[fall[i]][j-1]; for (int j=1;j<=d;j++) g[x][j]=min(g[x][j],g[x][j-1]); } } inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar()) x=x*10+c-48; } inline void add(int x,int y) { fall[++tot]=y;net[tot]=head[x];head[x]=tot; } void write(int x){ if (x<10) { putchar(‘0‘+x);return;} write(x/10),putchar(‘0‘+x%10); } inline void writeln(int x){ if (x<0) putchar(‘-‘),x*=-1; write(x); putchar(‘\n‘); } using namespace std; int main () { // freopen("a.in","r",stdin); read(n); read(d); for (int i=1;i<=n;i++) read(w[i]); read(m); for (int i=1;i<=m;i++) read(X),u[X]=1; for (int i=1;i< n;i++) read(A),read(B), add(A,B),add(B,A); dfs(1,0); writeln(f[1][0]); return 0; }