传送门
虚树入门。
值得注意的是,一个关键点的子树中的关键点是不用考虑的。
因为我们必须断掉所有关键点,意味着该关键点必须被断掉,那么它的子树就全部断掉了。
于是
i
n
s
e
r
t
insert
insert函数有一些变化。
inline void insert(int u){
if(top==1){stk[++top]=u;return;}
int g=lca(u,stk[top]);
if(g==stk[top]){return;}
while(top>1&&dfn[g]<=dfn[stk[top-1]])
re_add(stk[top-1],stk[top]),top--;
if(g!=stk[top]) re_add(g,stk[top]),stk[top]=g;
stk[++top]=u;
}
当
g
=
=
s
t
k
[
t
o
p
]
g==stk[top]
g==stk[top],不需要把
u
u
u入栈。
因为它一定在
s
t
k
[
t
o
p
]
stk[top]
stk[top]的子树中。而
s
t
k
[
t
o
p
]
stk[top]
stk[top]是关键点,当
s
t
k
[
t
o
p
]
stk[top]
stk[top]被断,
u
u
u自然也断了。
注意开 l o n g l o n g long long longlong。还有,最小值的初始化要足够大。
虚树的重置在树形DP里面。每个点搜完之后把新的 h e a d head head置为0,就相当于把新建的虚树清空了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=250010;
const ll oo=9e18;
int n,m,k,u,v,w;
int Head[maxn],Next[maxn<<1],V[maxn<<1],cnt=0;
int head[maxn],nxt[maxn<<1],to[maxn<<1],cntt=0;
int f[maxn][19],dep[maxn],dfn[maxn],tot=0;
int stk[maxn],x[maxn],top=0;
ll dp[maxn],dis[maxn],W[maxn<<1];
inline void add(int u,int v,ll w){Next[++cnt]=Head[u],V[cnt]=v,W[cnt]=w,Head[u]=cnt;}
inline void re_add(int u,int v){nxt[++cntt]=head[u],to[cntt]=v,head[u]=cntt;}
inline bool cmp(int a,int b){return dfn[a]<dfn[b];}
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
inline void dfs(int u,int fa){
dfn[u]=++tot,f[u][0]=fa,dep[u]=dep[fa]+1;
for(int i=1;i<=18;++i) f[u][i]=f[f[u][i-1]][i-1];
for(int i=Head[u];i;i=Next[i]) if(V[i]!=fa)
dis[V[i]]=min(W[i],dis[u]),dfs(V[i],u);
}
inline int lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=18;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i];
if(u==v) return u;
for(int i=18;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][0];
}
inline void insert(int u){
if(top==1){stk[++top]=u;return;}
int g=lca(u,stk[top]);
if(g==stk[top]){return;}
while(top>1&&dfn[g]<=dfn[stk[top-1]])
re_add(stk[top-1],stk[top]),top--;
if(g!=stk[top]) re_add(g,stk[top]),stk[top]=g;
stk[++top]=u;
}
inline void re_dfs(int u){
dp[u]=dis[u];ll sum=0;
for(int i=head[u];i;i=nxt[i])
re_dfs(to[i]),sum+=dp[to[i]];
if(sum) dp[u]=min(dp[u],sum);
head[u]=0;
}
int main(){
dis[1]=oo,n=read();
for(int i=1;i<n;++i) u=read(),v=read(),w=(ll)read(),add(u,v,w),add(v,u,w);
dfs(1,0),m=read();
while(m--){
cntt=0,top=0,stk[++top]=1,k=read();
for(int i=1;i<=k;++i) x[i]=read();
sort(x+1,x+k+1,cmp);
for(int i=1;i<=k;++i) insert(x[i]);
while(--top) re_add(stk[top],stk[top+1]);
re_dfs(1);printf("%lld\n",dp[1]);
}
}