网上写的都看不懂,自我感觉就是:把关键点排序,然后一开始根节是一条链,然后依次加入每一个点,每次用当前的路径,把求出新加入的点到根的路径,减去,也就是只保留那些从根到当前这个点的路径的点,可以想象是用新加入的路径切掉之前路径,这个题建完虚树随便做。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#define QwQ printf("FAKE\n");
#define N 250010
#define M N<<1
#define LOG 20
#define lint long long
#define INF (LLONG_MAX/100LL-100LL)
#define inf (INT_MAX/10-10)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int stc[N],d[N],up[N][LOG],minv[N][LOG],in[N],a[N];
int list[N],val[N],Log[N];lint f[N];bool mark[N];
struct edges{
int to,pre,w;
}e[M];int h[N],etop,cnt,dfs_clock,top;
inline int add_edge(int u,int v,int w)
{
// debug(u)sp,debug(v)sp,debug(w)sp,debug(etop)sp,debug(h[u])ln;
return e[++etop].to=v,e[etop].w=w,e[etop].pre=h[u],h[u]=etop;
}
int dfs(int x,int fa)
{
d[x]=d[fa]+1,in[x]=++dfs_clock;
for(int i=1;i<=Log[d[x]];i++)
up[x][i]=up[up[x][i-1]][i-1],
minv[x][i]=min(minv[x][i-1],minv[up[x][i-1]][i-1]);
for(int i=h[x],y;i;i=e[i].pre)
if((y=e[i].to)^fa) up[y][0]=x,minv[y][0]=e[i].w,dfs(y,x);
return 0;
}
inline int getLCA(int x,int y,int &w1,int &w2)
{
bool f=false;w1=w2=inf;
if(d[x]<d[y]) swap(x,y),f=true;
for(int i=Log[d[x]];i>=0;i--)
if(d[up[x][i]]>=d[y])
w1=min(w1,minv[x][i]),x=up[x][i];
if(x==y) return (x+y)>>1;
for(int i=Log[d[x]];i>=0;i--)
if(up[x][i]^up[y][i])
w1=min(w1,minv[x][i]),
w2=min(w2,minv[y][i]),
x=up[x][i],y=up[y][i];
w1=min(w1,minv[x][0]),
w2=min(w2,minv[y][0]),
x=up[x][0],y=up[y][0];
if(f) swap(w1,w2);return x;
}
inline int build_virtual(int *a,int n)//after sorting
{
etop=d[stc[val[list[cnt=stc[top=1]=1]=1]=0]=0]=0;
// for(int i=1;i<=n;i++) debug(i)sp,debug(a[i])ln;
for(int i=1;i<=n;i++)
{
int x=a[i],y=stc[top],z=stc[top-1],w1=0,w2=0,c;
while(d[c=getLCA(x,y,w1,w2)]<=d[z])
// debug(x)sp,debug(y)sp,debug(c)sp,debug(z)sp,debug(d[c])sp,debug(d[z])ln,
add_edge(z,y,val[top--]),y=z,z=stc[top-1];
if(c^y) add_edge(c,y,w2),stc[top]=c,getLCA(c,z,val[top],w2),list[++cnt]=c;
stc[++top]=x,val[top]=w1,list[++cnt]=x;
}
while(top>1) add_edge(stc[top-1],stc[top],val[top]),top--;
return 0;
}
inline lint get_ans(int x)
{
if(mark[x]) return f[x]=INF;
for(int i=h[x];i;i=e[i].pre)
f[x]+=min(get_ans(e[i].to),(lint)e[i].w);
return f[x];
}
inline bool cmp(int a,int b)
{
return in[a]<in[b];
}
int main()
{
int n;scanf("%d",&n);
for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(int i=1,ct;i<n;i++)
{
int u,v;scanf("%d%d%d",&u,&v,&ct);
add_edge(u,v,ct),add_edge(v,u,ct);
}
dfs(1,0);int m;scanf("%d",&m);
memset(h,0,sizeof(h));
/* for(int i=1;i<=n;i++)
{
debug(i)sp,debug(d[i])sp,debug(in[i])ln;
for(int j=0;j<=Log[d[i]];j++)
debug(j)sp,debug(up[i][j])sp,debug(minv[i][j])ln;
cerr ln;
}
while(1)
{
int x,y,w1,w2,c;cin>>x>>y;
c=getLCA(x,y,w1,w2);
debug(x)sp,debug(y)sp,debug(c)sp,debug(w1)sp,debug(w2)ln;
}*/
while(m--)
{
int k;scanf("%d",&k);
for(int i=1;i<=k;i++)
scanf("%d",&a[i]),mark[a[i]]=true;
sort(a+1,a+k+1,cmp);
build_virtual(a,k),printf("%lld\n",get_ans(1));
for(int i=1,x;i<=cnt;i++) h[x=list[i]]=0,f[x]=0ll;
for(int i=1;i<=k;i++) mark[a[i]]=false;
}
return 0;
}