开一个dp[maxn][2]的数组,记录以i为根的子树满足要求的最小花费,0代表i没和一个标记连在一起,1代表i和一个标记连在一起。
然后转移即可....
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=100005;
const ll inf=0x3fffffffffffffffLL;
struct edge
{
int to,next,cost;
}ee[maxn*2];
int e[maxn],ecnt;
void addedge(int u,int v,int t)
{
ee[ecnt].to=v;ee[ecnt].cost=t;ee[ecnt].next=e[u];e[u]=ecnt++;
ee[ecnt].to=u;ee[ecnt].cost=t;ee[ecnt].next=e[v];e[v]=ecnt++;
}
ll dp[maxn][2];
bool hash[maxn];
void dfs(int f,int u)
{
// cout<<"************"<<u<<endl;
if(hash[u])
{
dp[u][0]=inf;
dp[u][1]=0;
int i,v,w;
for(i=e[u];i!=-1;i=ee[i].next)
{
v=ee[i].to;w=ee[i].cost;
if(v==f)
continue;
dfs(u,v);
dp[u][1]+=min(dp[v][0],dp[v][1]+w);
}
return ;
}
else
{
dp[u][0]=0;
dp[u][1]=inf;
int i,j,v,w;
for(i=e[u];i!=-1;i=ee[i].next)
{
v=ee[i].to;w=ee[i].cost;
if(v==f)
continue;
dfs(u,v);
dp[u][0]+=min(dp[v][0],dp[v][1]+w);
}
for(i=e[u];i!=-1;i=ee[i].next)
{
v=ee[i].to;w=ee[i].cost;
if(v==f)
continue;
dp[u][1]=min(dp[u][1],dp[u][0]-min(dp[v][0],dp[v][1]+w)+dp[v][1]);
}
return ;
}
}
int main()
{
int t;
int n,k,i,j,u,v,w;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
memset(e,-1,sizeof(e));ecnt=0;
for(i=1;i<n;++i)
{
scanf("%d%d%d",&u,&v,&w);
u++;v++;
addedge(u,v,w);
}
memset(hash,false,sizeof(hash));
for(i=1;i<=k;++i)
{
scanf("%d",&u);
u++;
hash[u]=true;
}
dfs(-1,1);
printf("%I64d\n",min(dp[1][0],dp[1][1]));
}
return 0;
}