• 【HNOI2014】世界树


    P2354 - 【HNOI2014】世界树

    Description

    世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
    世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相 同。有的聚居地之间有双向的道路相连,道路的长度为1。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居 地之间的距离为连接他们的道路的长度;例如,若聚居地a和b之间有道路,b和c之间有道路,因为每条道路长度为1而且又不可能出现环,所卧a与c之间的距 离为2。
    出于对公平的考虑,第i年,世界树的国王需要授权m[i]个种族的聚居地为临时议事处。对于某个种族x(x为种族的编号),如果距离该种族最近的临时议事 处为y(y为议事处所在聚居地的编号),则种族x将接受y议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则y为其中编号最小的临时议事处)。
    现在国王想知道,在q年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

    Input

    第一行为一个正整数n,表示世界树中种族的个数。
    接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双向道路。接下来一行为一个正整数q,表示国王询问的年数。
    接下来q块,每块两行:
    第i块的第一行为1个正整数m[i],表示第i年授权的临时议事处的个数。
    第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被授权为临时议事处的聚居地编号(保证互不相同)。

    Output

    输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。

    Sample Input

    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

    Sample Output

    1 9
    3 1 4 1 1
    10
    1 1 3 5
    4 1 3 1 1

    Hint

    N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000

     
    所谓虚树,就是一个把在原树中询问的结点和相关结点(LCA)取出来重新建的一个树。这样可以大大减少复杂度,但不会影响答案。
    虚树的建树过程:
    把询问点按照原树中的dfn排序。
    开一个栈,根节点放入栈中。
    枚举询问点,若这个点与栈顶元素的LCA就是栈顶元素,则直接放入栈中,否则:
    若栈顶的下一个元素的deep大于LCAdeep,top-1top连边,弹栈。
    直到栈顶的下一个元素的deep小于等于LCAdeep,栈顶和LCA连边,弹栈,插入LCA
    (注意这里的
    LCA一直是最初的那个LCA)最后插入这个询问点。
    这道题每一个询问建一颗虚树,然后再把虚树上的点的归属点都找到,用两遍DFS
    一遍用儿子更新,一遍用父亲更新。
    然后就考虑没有在虚树上的点,用一个数组记录一下虚树上的每一个结点未处理的点的数量,初值就是size
    然后枚举虚树上的每一条边,若这条边连的两个点的归属点相同那么直接加上size的差即可。
    若不同,则用倍增找分界点,然后分别加答案。然后这个两个点之间的点都被处理了,把这些点减去即可。
    然后还要把没统计到的点统计一遍。
    真的变态。
      1 #include<set>
      2 #include<map>
      3 #include<queue>
      4 #include<stack>
      5 #include<ctime>
      6 #include<cmath>
      7 #include<string>
      8 #include<vector>
      9 #include<cstdio>
     10 #include<cstdlib>
     11 #include<cstring>
     12 #include<iostream>
     13 #include<algorithm>
     14 #define maxn 300010
     15 using namespace std;
     16 struct data{
     17   int nex,to;
     18 }e[maxn*2];//原树
     19 data g[maxn*2];//虚树
     20 int head[maxn],edge=0,head1[maxn],edge1=0,gg[maxn],belong[maxn],ans[maxn],dfn[maxn],size[maxn],deep[maxn];
     21 int f[maxn][20],a[maxn],b[maxn];
     22 int Stack[maxn];
     23 void add(int from,int to){
     24   e[++edge].nex=head[from];
     25   e[edge].to=to;
     26   head[from]=edge;
     27 }
     28 void link(int from,int to){ //建虚树边
     29   g[++edge1].nex=head1[from];
     30   g[edge1].to=to;
     31   head1[from]=edge1;
     32 }
     33 int de=0;
     34 void dfs1(int x,int fa){
     35   de++;
     36   dfn[x]=de;
     37   size[x]++;
     38   for(int i=head[x];i;i=e[i].nex){
     39     int u=e[i].to;
     40     if(u==fa) continue;
     41     deep[u]=deep[x]+1;
     42     f[u][0]=x;
     43     dfs1(u,x);
     44     size[x]+=size[u];
     45   }
     46 }
     47 int lca(int x,int y){
     48   if(deep[x]<deep[y])swap(x,y);
     49   for(int i=18;i>=0;i--)
     50     if(deep[x]-(1<<i)>=deep[y]) x=f[x][i];
     51   if(x==y) return x;
     52   for(int i=18;i>=0;i--)
     53     if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
     54   return f[x][0];
     55 }
     56 int getdis(int x,int y){
     57   return deep[x]+deep[y]-2*deep[lca(x,y)];
     58 }
     59 void DFS1(int x,int fa){ //找归属点
     60   int d1,d2;
     61   gg[x]=size[x];
     62   for(int i=head1[x];i;i=g[i].nex){
     63     int u=g[i].to;
     64     if(u==fa) continue;
     65     DFS1(u,x);if(!belong[u]) continue;
     66     if(!belong[x]){belong[x]=belong[u];continue;}
     67     d1=getdis(belong[u],x);d2=getdis(belong[x],x);
     68     if(d1<d2 || (d1==d2 && belong[u]<belong[x])) belong[x]=belong[u];
     69   }
     70 }
     71 void DFS2(int x,int fa){
     72   int d1,d2;
     73   for(int i=head1[x];i;i=g[i].nex){
     74    int u=g[i].to;
     75    if(u==fa) continue;
     76    if(!belong[u]) belong[u]=belong[x];
     77    else{
     78      d1=getdis(belong[u],u),d2=getdis(belong[x],u);
     79      if(d1>d2 || (d1==d2 && belong[x]<belong[u])) belong[u]=belong[x];
     80    }
     81    DFS2(u,x);
     82  }
     83 }
     84 bool cmp(int a,int b){
     85   return dfn[a]<dfn[b];
     86 }
     87 int build(){
     88   int tot,top=0,LCA;scanf("%d",&tot);
     89   for(int i=1;i<=tot;i++) scanf("%d",&a[i]),b[i]=a[i],belong[a[i]]=a[i];
     90   sort(a+1,a+tot+1,cmp);
     91   if(!belong[1]) Stack[++top]=1;
     92   for(int i=1;i<=tot;i++){//建虚树
     93     if(top==0) {Stack[++top]=a[i];continue;}
     94     LCA=lca(Stack[top],a[i]);
     95     while(1){
     96       if(deep[Stack[top-1]]<=deep[LCA]){
     97     if(LCA!=Stack[top]) link(LCA,Stack[top]),link(Stack[top],LCA);
     98     top--;
     99     if(Stack[top]!=LCA) Stack[++top]=LCA;
    100     break;
    101       }
    102       link(Stack[top-1],Stack[top]),link(Stack[top],Stack[top-1]);
    103       top--;
    104     }
    105     if(Stack[top]!=a[i]) Stack[++top]=a[i];
    106   }
    107   while(top>1) link(Stack[top-1],Stack[top]),link(Stack[top],Stack[top-1]),top--;
    108   top--;
    109   DFS1(1,0);
    110   DFS2(1,0);
    111   return tot;
    112 }
    113 void solve(int fa,int u){
    114   int son=u,mid=u,d1,d2;
    115   for(int i=18;i>=0;i--)
    116     if(deep[son]-(1<<i)>deep[fa]) son=f[son][i];
    117   gg[fa]-=size[son];
    118   if(belong[fa]==belong[u]){ans[belong[fa]]+=size[son]-size[u];return;}
    119   for(int i=18;i>=0;i--)
    120     if(deep[f[mid][i]]>deep[fa]){
    121       d1=getdis(f[mid][i],belong[fa]),d2=getdis(f[mid][i],belong[u]);
    122       if(d1>d2 || (d1==d2 && belong[u]<belong[fa])) mid=f[mid][i];
    123     }
    124   ans[belong[fa]]+=size[son]-size[mid];
    125   ans[belong[u]]+=size[mid]-size[u];
    126 }
    127 int main()
    128 {
    129   freopen("!.in","r",stdin);
    130   freopen("!.out","w",stdout);
    131   int n,x,y,qes;
    132   scanf("%d",&n);
    133   for(int i=1;i<n;i++){
    134     scanf("%d%d",&x,&y);
    135     add(x,y),add(y,x);
    136   }
    137   deep[1]=1;
    138   dfs1(1,0);
    139   for(int i=1;i<=18;i++)
    140     for(int j=1;j<=n;j++)
    141       f[j][i]=f[f[j][i-1]][i-1];
    142   scanf("%d",&qes);
    143   for(int i=1;i<=qes;i++){
    144     int tot=build();
    145     for(int i=1;i<=edge1;i+=2){
    146       int u=g[i].to,v=g[i+1].to;
    147       if(deep[u]<deep[v]) swap(u,v);
    148       solve(v,u);
    149     }
    150     for(int i=1;i<=edge1;i++) ans[belong[g[i].to]]+=gg[g[i].to],gg[g[i].to]=0;
    151     for(int i=1;i<=tot;i++) printf("%d ",ans[b[i]]);
    152     printf("
    ");
    153     memset(ans,0,sizeof(ans));memset(gg,0,sizeof(gg));memset(belong,0,sizeof(belong));
    154     edge1=0;memset(head1,0,sizeof(head1));
    155   }
    156   return 0;
    157 }
  • 相关阅读:
    C++ 虚成员函数和动态联编
    C++ 多态公有继承
    C++ 继承特性
    C++ 公有派生
    C++ 基类与派生类
    C++ 类继承
    C++ 伪私有方法
    C++ new失败
    mysql用户授权
    linux时间设置
  • 原文地址:https://www.cnblogs.com/pantakill/p/6679646.html
Copyright © 2020-2023  润新知