题目

题目描述
世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。

世界树的形态可以用一个数学模型来描述:世界树中有 nn 个种族,种族的编号分别从 11 到 nn,分别生活在编号为 11 到 nn 的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为 11。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;例如,若聚居地 aa 和 bb 之间有道路,bb 和 cc 之间有道路,因为每条道路长度为 11 而且又不可能出现环,所以 aa 与 cc 之间的距离为 22。

出于对公平的考虑,第 ii 年,世界树的国王需要授权 m_im
i

个种族的聚居地为临时议事处。对于某个种族 xx(xx 为种族的编号),如果距离该种族最近的临时议事处为 yy(yy 为议事处所在聚居地的编号),则种族 xx 将接受 yy 议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则 yy 为其中编号最小的临时议事处)。

现在国王想知道,在 qq 年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

输入格式
第一行为一个正整数 nn,表示世界树中种族的个数。接下来 n-1n−1 行,每行两个正整数 x,yx,y,表示 xx 聚居地与 yy 聚居地之间有一条长度为 11 的双向道路。接下来一行为一个正整数 qq,表示国王询问的年数。接下来 qq 块,每块两行:第 ii 块的第一行为 11 个正整数 m_im
i

,表示第 ii 年授权的临时议事处的个数。第 ii 块的第二行为 m_im
i

个正整数 h_1, h_2,\ldots,h_{m_i}h
1

,h
2

,…,h
m
i


,表示被授权为临时议事处的聚居地编号(保证互不相同)。

输出格式
输出包含 qq 行,第 ii 行为 m_im
i

个整数,该行的第 jj (j=1, 2,\ldots, m_ij=1,2,…,m
i

) 个数表示第 ii 年被授权的聚居地 h_jh
j

的临时议事处管理的种族个数。

输入输出样例
输入 #1复制
10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8
输出 #1复制
1 9
3 1 4 1 1
10
1 1 3 5
4 1 3 1 1
说明/提示
对于 100%100% 的数据,N\leq 300000N≤300000, q\leq 300000q≤300000, \sum^q_{i=1}m_i \leq 300000∑
i=1
q

m
i

≤300000。

思路

虚树+超麻烦的dp
一个点x拥有的点:sz[x]-sz[儿子]

x,f[x] 分界点p(p上面的属于f[x])

则f[x]拥有的点:sz[p方向上的儿子]-sz[p]

x拥有的点:sz[p]-sz[x]

p与x的dis

dis+dis[x]=(dis(f[x],x)-dis)+dis[y]

dis=(dis(f[x],x)-dis[x]+dis[y])/2

dp时,每个点记录near[i] 最近点,dis[i] 与其距离

代码

#include<bits/stdc++.h>
using namespace std;
#define N 300077
int t[N];
struct E
{
    int to,next;
}l[2000000];
int e;
void add_e(int x,int y)
{
    l[++e]=(E){y,t[x]};t[x]=e;
}

struct tree
{
    int f[20],dep,sz,dfn;
}T[N];int tot;

void dfs(int x,int f,int dep)
{
    T[x].sz=1;T[x].dep=dep;
    T[x].f[0]=f;
    T[x].dfn=++tot;
    int i,y;
    for (i=0,y=f;y=T[y].f[i];T[x].f[++i]=y);

    ++dep;
    for (i=t[x];i;i=l[i].next)
    if ((y=l[i].to)!=f)
    {
      dfs(y,x,dep);
      T[x].sz+=T[y].sz; 
    }
}

int jump(int x,int l)
{
    for (int i=0;l;++i,l>>=1)
    if (l&1) x=T[x].f[i];
    return x;
}

int get_lca(int x,int y)
{
    if (T[x].dep<T[y].dep) swap(x,y);
    x=jump(x,T[x].dep-T[y].dep);
    if (x==y) return x;
    for (int i=19;i>=0;--i)
    if (T[x].f[i]!=T[y].f[i])
    {
        x=T[x].f[i];y=T[y].f[i];
    }
    return T[x].f[0];
} 

bool dfn_xiao(int x,int y)
{
    return T[x].dfn<T[y].dfn;
}
int i,x,y;
int q0[N],q[N],num0,num;
int st[N],top;
struct xutree
{
    int f;
    bool d;
}_T[N];
int near[N],dis[N],sz[N];
void build()
{
    sort(q+1,q+num+1,dfn_xiao);
    st[top=1]=q[1];
    _T[q[1]]=(xutree){0,1};
    for (i=2;i<=num0;++i)
    {
        x=q[i];
        int lca=get_lca(y=st[top],x);
        if (lca!=y)
        {
          while (T[lca].dep<T[st[top]].dep) y=st[top--];
          if (st[top]!=lca)
          {
            _T[y].f=lca;
            _T[lca]=(xutree){st[top],0};
            st[++top]=lca;q[++num]=lca;
          }
        }
        _T[x]=(xutree){st[top],1};st[++top]=x;
    }
    sort(q+1,q+num+1,dfn_xiao);
}

void upd(int _dis,int _near,int y)
{
    if (_dis<dis[y]||_dis==dis[y]&&_near<near[y])
    {
        dis[y]=_dis;near[y]=_near; 
    }
}

int n;
int ans[N];
void dp()
{
    int _dis;
    for (i=1;i<=num;++i) 
    {
        x=q[i];
        sz[x]=T[x].sz;
        if (_T[x].d) {near[x]=x;dis[x]=0;}
        else dis[x]=1<<30;  
    }
    for (i=num;i>1;--i)
    {
        x=q[i];y=_T[x].f;
        _dis=dis[x]+T[x].dep-T[y].dep;
        upd(_dis,near[x],y);
    }
    for (i=2;i<=num;++i)
    {
        x=q[i];y=_T[x].f;
        _dis=dis[y]+T[x].dep-T[y].dep;
        upd(_dis,near[y],x);
    }

    int k;
    for (i=num;i>1;--i)
    {
        x=q[i];y=_T[x].f;
        k=jump(x,T[x].dep-T[y].dep-1);
        sz[y]-=T[k].sz;
    }

    x=q[1];
    ans[near[x]]=sz[x]+n-T[x].sz;
    for (i=2;i<=num;++i)
    {
        x=q[i];
        ans[near[x]]+=sz[x];
        y=_T[x].f;k=jump(x,T[x].dep-T[y].dep-1);
        if (near[y]==near[x]) ans[near[x]]+=T[k].sz-T[x].sz;
        else
        {
            _dis=T[x].dep-T[y].dep-dis[x]+dis[y];
            if (_dis&1) _dis>>=1; else
            if (near[x]<near[y]) _dis>>=1;
            else (_dis>>=1)-=1;

            int p=jump(x,_dis);
            ans[near[x]]+=T[p].sz-T[x].sz;
            ans[near[y]]+=T[k].sz-T[p].sz; 
        }
    }
}

int main()
{
    freopen("1.in","r",stdin);

    scanf("%d",&n);
    for (i=1;i<n;++i) 
    {scanf("%d%d",&x,&y);
     add_e(x,y);add_e(y,x);
    }

    dfs(1,0,1);

    int m;
    scanf("%d",&m); 
    while (m--)
    {
        scanf("%d",&num);num0=num;
        for (i=1;i<=num;++i) {scanf("%d",q+i);q0[i]=q[i];}
        build();
        dp();
        for (i=1;i<=num0;++i) {printf("%d ",ans[q0[i]]);ans[q0[i]]=0;}
        printf("\n");
    }
}