题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2286
题解:看数据范围以及结合题目要求显然可以用虚树,然后建出来虚树在上面DP就好了
建虚树时以1为根,然后f[i]表示将以i为节点的子树(包括其自己)断开的费用,如果f[i]为有资源的点f[i]=min(w[1到i的路径]),如果i没有资源,就将f[i]再和sum[f[son[i]]]取个min就OK。
(代码一看就懂)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const LL inf=1e12;
const int N=250005;
const int M=500005;
int n,m,K,d[N*2],s[N*2],top;
int cnt,to[M],nxt[M],lj[N],w[M];
int cnt1,to1[M],nxt1[M],lj1[N];
void ins(int f,int t,int p) {cnt++,to[cnt]=t,nxt[cnt]=lj[f],lj[f]=cnt,w[cnt]=p;}
void add(int f,int t,int p) {ins(f,t,p),ins(t,f,p);}
void ins1(int f,int t) {cnt1++,to1[cnt1]=t,nxt1[cnt1]=lj1[f],lj1[f]=cnt1;}
void add1(int f,int t)
{
if(f==t) return;
ins1(f,t);
ins1(t,f);
}
int fa[N],dep[N],anc[N][20],pos[N],tar,Log[N];
LL dis[N];
bool cmp(int x,int y) {return pos[x]<pos[y];}
void dfs(int x)
{
pos[x]=++tar;
dep[x]=dep[fa[x]]+1;
for(int i=lj[x];i;i=nxt[i])
if(to[i]!=fa[x])
{
fa[to[i]]=x;
anc[to[i]][0]=x;
dis[to[i]]=min(dis[x],(LL)w[i]);
dfs(to[i]);
}
}
void pre()
{
Log[0]=-1;
for(int i=1;i<=n;i++) Log[i]=Log[i>>1]+1;
for(int j=1;j<=Log[n];j++)
for(int i=1;i<=n;i++)
anc[i][j]=anc[anc[i][j-1]][j-1];
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
int deep=dep[x]-dep[y];
for(int i=0;i<=Log[deep];i++)
if(deep&(1<<i)) x=anc[x][i];
if(x==y) return x;
for(int i=Log[n];i>=0;i--)
if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i];
return fa[x];
}
LL f[N];
bool b[N];
void dfs1(int x,int fa)
{
LL sum=0;
for(int i=lj1[x];i;i=nxt1[i])
if(to1[i]!=fa)
{
dfs1(to1[i],x);
sum+=f[to1[i]];
}
if(b[x]) f[x]=dis[x];
else f[x]=min(sum,dis[x]);
lj1[x]=b[x]=0;
}
int main()
{
scanf("%d",&n);
int x,y,z;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
dis[1]=inf;
dfs(1);
pre();
scanf("%d",&m);
while(m--)
{
scanf("%d",&K);
for(int i=1;i<=K;i++) scanf("%d",&d[i]),b[d[i]]=true;
sort(d+1,d+K+1,cmp);
top=cnt1=0;
s[++top]=1;
for(int i=1;i<=K;i++)
{
int tmp=lca(s[top],d[i]);
while(top>1&&dep[s[top-1]]>=dep[tmp])
{
add1(s[top-1],s[top]);
top--;
}
add1(s[top],tmp);
s[top]=tmp;
s[++top]=d[i];
}
for(int i=1;i<top;i++) add1(s[i],s[i+1]);
dfs1(1,0);
printf("%lld\n",f[1]);
}
}