题解:对询问点建立虚树
然后在虚树上Dp
每个点父边边权为这个点到根的边权最小值
一开始学了假的虚树
一开始竟然没想到父边边权可以这样赋
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<algorithm> using namespace std; const int maxn=500009; const int inf=2000000000; typedef long long Lint; int n,m,T; int cntedge; int head[maxn]; int to[maxn],nex[maxn],dist[maxn]; void Addedge(int x,int y,int z){ // cout<<x<<‘ ‘<<y<<‘ ‘<<z<<endl; nex[++cntedge]=head[x]; to[cntedge]=y; dist[cntedge]=z; head[x]=cntedge; } int dfsclock; int father[maxn],depth[maxn],minedge[maxn]; int L[maxn],R[maxn]; void Dfs(int now,int fa,int ecost){ L[now]=++dfsclock; father[now]=fa; depth[now]=depth[fa]+1; minedge[now]=min(minedge[fa],ecost); for(int i=head[now];i;i=nex[i]){ if(to[i]==fa)continue; Dfs(to[i],now,dist[i]); } R[now]=++dfsclock; } int f[maxn][20]; void LCAinit(){ for(int i=1;i<=n;++i)f[i][0]=father[i]; for(int j=1;j<=19;++j){ for(int i=1;i<=n;++i){ f[i][j]=f[f[i][j-1]][j-1]; } } } int Getlca(int u,int v){ if(depth[u]<depth[v])swap(u,v); for(int j=19;j>=0;--j){ if(depth[f[u][j]]>=depth[v])u=f[u][j]; } if(u==v)return u; for(int j=19;j>=0;--j){ if(f[u][j]!=f[v][j]){ u=f[u][j];v=f[v][j]; } } return f[u][0]; } int h[maxn]; int ene[maxn]; int cmp(const int &rhs1,const int &rhs2){ return L[rhs1]<L[rhs2]; } int S[maxn],top; inline int intree(int x,int y){ return (L[x]>=L[y])&&(R[x]<=R[y]); } Lint g[maxn]; int q[maxn]; void Dp(int x,int fa){ if(ene[x]){ q[x]=1;g[x]=inf;return; } q[x]=g[x]=0; for(int i=head[x];i;i=nex[i]){ if(to[i]==fa)continue; Dp(to[i],x); q[x]|=q[to[i]]; if(q[to[i]])g[x]+=min(g[to[i]],dist[i]*1LL); } } int Xsize; int a[maxn]; int main(){ scanf("%d",&n); for(int i=1;i<=n-1;++i){ int x,y,z; scanf("%d%d%d",&x,&y,&z); Addedge(x,y,z); Addedge(y,x,z); } minedge[0]=inf; Dfs(1,0,inf); LCAinit(); memset(head,0,sizeof(head)); scanf("%d",&T); while(T--){ // cout<<"begin"<<endl; scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&h[i]);ene[h[i]]=1; } sort(h+1,h+1+n,cmp); // for(int i=1;i<=n;++i)cout<<h[i]<<‘ ‘; // cout<<endl; cntedge=Xsize=0; S[top=1]=1;a[++Xsize]=1; for(int i=1;i<=n;++i){ int lca=Getlca(h[i],S[top]); while(!intree(h[i],S[top])){ if(intree(lca,S[top-1])){ Addedge(lca,S[top],minedge[S[top]]);--top;break; } Addedge(S[top-1],S[top],minedge[S[top]]);--top; } if(S[top]!=lca){ S[++top]=lca;a[++Xsize]=lca; } S[++top]=h[i];a[++Xsize]=h[i]; } while(top>1){ Addedge(S[top-1],S[top],minedge[S[top]]);--top; } Dp(1,0); printf("%lld\n",g[1]); for(int i=1;i<=Xsize;++i){ ene[a[i]]=head[a[i]]=0; } } return 0; }