思路:首先因为n的范围很大,考虑建立虚树,就是把大部分的冗余的点去掉然后建立一颗新的树然后再树形dp,具体实现可以考虑用一个栈维护,首先求出每个点的dfn然后按照dfn排序,然后用一个栈维护(栈里存的关键点或关键点之间的lca或关键点lca的lca等等。。。),然后枚举关键点,求出关键点与当前栈顶元素的lca,如果当前栈顶元素就是当前关键点的父亲(也就是他们的lca就是栈顶元素),直接就把当前关键点push进栈,否则就可以直接连边了,将stack[top-1]向stack[top]连边,因为此时lca一定是stack[top]的祖先,这样连边显然没有问题,当然要判一下dfn[stack[top-1]]是否大于等于dfn[lca],因为只有stack[top-1]也是lca的后代时才能连边,如果dfn[stack[top-1]]<dfn[lca]说明stack[top-1]为lca的祖先(是祖先不能是兄弟,因为如果是兄弟一定会在处理当前栈顶元素时就已经弹出栈了),这时显然就不能连边了,然后把lca也push进栈就行了(记得判一下可能lca已经在栈中,对应的就是dfn[stack[top-1]]==dfn[lca]),其本质也就是维护最右边的那条链,一旦有点不属于最右边的那条链直接连边就好了,最后栈中剩下的元素也一定是最右边的那条链中的元素,直接连边就好了。
然后就tree dp就好了。我写的比较丑,多维护了很多东西,凑合着看吧。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 1000005
#define inf 1e9
int n,q,tot,top,ans1,ans2,deg,l;
int now[maxn],pre[2*maxn],son[2*maxn],dep[maxn],stack[maxn],a[maxn];
int maxdis[maxn],mindis[maxn],size[maxn],dfn[maxn];
long long sum[maxn],sumdep[maxn];
int f[maxn][21];
bool bo[maxn];
inline int read(){
int x=0;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
void add(int a,int b){
son[++tot]=b;
pre[tot]=now[a];
now[a]=tot;
}
void link(int a,int b){
add(a,b),add(b,a);
}
void dfs(int x,int fa){
dep[x]=dep[fa]+1,dfn[x]=++deg;
for (int i=1;i<=l;i++) f[x][i]=f[f[x][i-1]][i-1];
for (int p=now[x];p;p=pre[p])
if (son[p]!=fa) f[son[p]][0]=x,dfs(son[p],x);
}
int lca(int a,int b){
if (dep[a]<dep[b]) swap(a,b);int x=dep[a]-dep[b],t=0;
for (;x;x>>=1,t++) if (x&1) a=f[a][t];t=l;
if (a==b) return a;
for (;f[a][0]!=f[b][0];){
for (;f[a][t]==f[b][t];t--);
a=f[a][t],b=f[b][t];
}
return f[a][0];
}
bool cmp(int a,int b){return dfn[a]<dfn[b];}
void tree_dp(int x){
long long s=0;
mindis[x]=inf,size[x]=0,sum[x]=maxdis[x]=0,sumdep[x]=0;
for (int p=now[x];p;p=pre[p]){
tree_dp(son[p]);int d=dep[son[p]]-dep[x];
if (bo[x]) sum[x]+=sumdep[son[p]]+size[son[p]]*d;
sum[x]+=sum[son[p]]+s*size[son[p]]+(sumdep[son[p]]+1ll*size[son[p]]*d)*size[x];
ans1=min(ans1,mindis[x]+mindis[son[p]]+d);
ans2=max(ans2,maxdis[x]+maxdis[son[p]]+d);
mindis[x]=min(mindis[x],mindis[son[p]]+d);
maxdis[x]=max(maxdis[x],maxdis[son[p]]+d);
s+=sumdep[son[p]]+1ll*d*size[son[p]],size[x]+=size[son[p]];
}
size[x]+=bo[x],sumdep[x]=s;
if (bo[x]) ans1=min(ans1,mindis[x]),ans2=max(ans2,maxdis[x]),mindis[x]=0;
now[x]=0;
}
int main(){
n=read();l=log2(n);
for (int i=1,u,v;i<n;i++) u=read(),v=read(),link(u,v);
dfs(1,0);memset(now,0,sizeof(now)),tot=0;
q=read();
while (q--){
n=read();for (int i=1;i<=n;i++) a[i]=read(),bo[a[i]]=1;
top=0,ans1=inf,ans2=0;sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;i++){
if (!top){stack[++top]=a[i];continue;}
int x=lca(stack[top],a[i]);
for (;dfn[x]<dfn[stack[top]];){
if (dfn[x]>=dfn[stack[top-1]]){
add(x,stack[top]);
if (stack[--top]!=x) stack[++top]=x;
break;
}
add(stack[top-1],stack[top]),top--;
}
stack[++top]=a[i];
}
while (top>1) add(stack[top-1],stack[top]),top--;
tree_dp(stack[1]);
printf("%lld %d %d
",sum[stack[1]],ans1,ans2);
for (int i=1;i<=n;i++) bo[a[i]]=0;tot=0;
}
return 0;
}