传送门

挂上点分治的标签是因为如果数据范围小一点我就真的去写点分了。。。

先把虚树造出来。统计所有路径的最值和权值和。。。点分治!

成功被数据范围拦了下来。。。(刚学点分治和虚树的我表示两样能一块练多好)

考虑$DP$,最大值类似于树的直径,只不过两端点必须为关键点。

设$ma(i)$为以点$i$到其子树中的关键点的最长路径长度。若$i$为关键点,$ma(i)$初值为$0$,否则为$-inf$,然后和树的直径一样$DP$即可。最小值类似。

对于权值和,记$siz(i)$为点$i$的子树中关键点的个数(包括$i$),$len(i)$为点$i$到其子树中所有关键点的路径权值之和。

显然,$siz(i)=\sum\limits_{edge(i,j)}siz(j)$,$len(i)=\sum\limits_{edge(i,j)}len(j)+siz(j)*length(edge(i,j))$。

对答案的贡献即$\sum\limits_{edge(i,j)}siz(i)*[len(j)+siz(j)*length(edge(i,j))]+siz(j)*len(i)$,注意此处的$siz(i)$和$len(i)$是统计到$j$时的值。

其实还有更简单的方法,直接统计每条边被经过的次数乘上边长,即$length(edge(i,j))*siz(j)*(k-siz(j))$

复杂度$O(\sum k\log n)$,$\log n$是小常数树剖$lca$和排序。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>

#define maxn 1000005
#define inf 0x3f3f3f3f

using namespace std;

inline int read(){
    int x=0,y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
struct edge{
    int pre,to,l;
};
namespace origin{
    int h[maxn],seg[maxn],top[maxn],son[maxn],fa[maxn],deep[maxn],siz[maxn],num,all;
    edge e[maxn<<1];
    inline void add(int from,int to){
        e[++num].pre=h[from],h[from]=num,e[num].to=to;
    }
    void dfs1(int node=1){
        siz[node]=1;
        int x;
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            if(!siz[x]){
                fa[x]=node,deep[x]=deep[node]+1;
                dfs1(x),siz[node]+=siz[x];
                if(siz[x]>siz[son[node]])son[node]=x;
            }
        }
    }
    void dfs2(int node=1){
        seg[node]=++all;
        if(son[node]){
            top[son[node]]=top[node],dfs2(son[node]);
            int x;
            for(register int i=h[node];i;i=e[i].pre){
                x=e[i].to;
                if(!seg[x])top[x]=x,dfs2(x);
            }
        }
    }
    int lca(int x,int y){
        while(top[x]!=top[y])deep[top[x]]<deep[top[y]]?y=fa[top[y]]:x=fa[top[x]];
        return deep[x]<deep[y]?x:y;
    }
}
namespace virt{
    int ma[maxn],mi[maxn],h[maxn],siz[maxn],num,ans2,ans3;
    long long len[maxn],ans1;
    bool vis[maxn];
    vector<int>p;
    edge e[maxn<<1];
    inline void add(int from,int to){
        int l=abs(origin::deep[from]-origin::deep[to]);
        e[++num].pre=h[from],h[from]=num,e[num].to=to,e[num].l=l;
        e[++num].pre=h[to],h[to]=num,e[num].to=from,e[num].l=l;
    }
    struct Monostack{
        int sta[maxn],top;
        void clear(){
            for(register int i=2;i<=top;++i)add(sta[i],sta[i-1]);
            top=0;
        }
        void push(int x){
            sta[++top]=x;
        }
        void check(int x){
            if(x==1)return;
            int l=origin::lca(x,sta[top]);
            h[x]=0;
            if(l!=sta[top]){
                while(origin::seg[l]<origin::seg[sta[top-1]])add(sta[top],sta[top-1]),--top;
                --top;
                if(l!=sta[top])h[l]=0,add(sta[top+1],l),push(l);
                else add(sta[top+1],l);
            }
            push(x);
        }
    }s;
    inline bool cmp(int x,int y){
        return origin::seg[x]<origin::seg[y];
    }
    void build(){
        h[1]=0,s.push(1);
        for(vector<int>::iterator iter=p.begin();iter!=p.end();++iter)s.check(*iter);
        s.clear();
    }
    void dfs(int node=1,int f=0){
        siz[node]=vis[node],len[node]=0,mi[node]=vis[node]?0:inf,ma[node]=vis[node]?0:-inf;
        int x;
        long long l;
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            if(x==f)continue;
            dfs(x,node);
            l=len[x]+1ll*e[i].l*siz[x];
            ans1+=siz[node]*l+siz[x]*len[node];
            siz[node]+=siz[x],len[node]+=l;
            ans2=min(ans2,mi[node]+mi[x]+e[i].l);
            ans3=max(ans3,ma[node]+ma[x]+e[i].l);
            mi[node]=min(mi[node],mi[x]+e[i].l);
            ma[node]=max(ma[node],ma[x]+e[i].l);
        }    
    }
    void solve(){
        p.clear(),num=ans1=ans3=0,ans2=inf;
        int n=read(),x;
        for(register int i=1;i<=n;++i)p.push_back(x=read()),vis[x]=1;
        sort(p.begin(),p.end(),cmp);
        build(),dfs();
        printf("%lld %d %d\n",ans1,ans2,ans3);
        for(vector<int>::iterator iter=p.begin();iter!=p.end();++iter)vis[*iter]=0;
    }
}
int main(){
    int n=read(),x,y;
    for(register int i=1;i<n;++i)x=read(),y=read(),origin::add(x,y),origin::add(y,x);
    origin::dfs1(),origin::dfs2();
    n=read();
    while(n--)virt::solve();
}