zoukankan      html  css  js  c++  java
  • bzoj4539: [Hnoi2016]树

    Description

      小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了。开始,小A只有一棵结点数为N的树,结
    点的编号为1,2,…,N,其中结点1为根;我们称这颗树为模板树。小A决定通过这棵模板树来构建一颗大树。构建过
    程如下:(1)将模板树复制为初始的大树。(2)以下(2.1)(2.2)(2.3)步循环执行M次(2.1)选择两个数字a,b,
    其中1<=a<=N,1<=b<=当前大树的结点数。(2.2)将模板树中以结点a为根的子树复制一遍,挂到大树中结点b的下
    方(也就是说,模板树中的结点a为根的子树复制到大树中后,将成为大树中结点b的子树)。(2.3)将新加入大树
    的结点按照在模板树中编号的顺序重新编号。例如,假设在进行2.2步之前大树有L个结点,模板树中以a为根的子
    树共有C个结点,那么新加入模板树的C个结点在大树中的编号将是L+1,L+2,…,L+C;大树中这C个结点编号的大小
    顺序和模板树中对应的C个结点的大小顺序是一致的。下面给出一个实例。假设模板树如下图:


    根据第(1)步,初始的大树与模板树是相同的。在(2.1)步,假设选择了a=4,b=3。运行(2.2)和(2.3)后,得到新的
    大树如下图所示

    现在他想问你,树中一些结点对的距离是多少。

    Input

      第一行三个整数:N,M,Q,以空格隔开,N表示模板树结点数,M表示第(2)中的循环操作的次数,Q 表示询问数
    量。接下来N-1行,每行两个整数 fr,to,表示模板树中的一条树边。再接下来M行,每行两个整数x,to,表示将模
    板树中 x 为根的子树复制到大树中成为结点to的子树的一次操作。再接下来Q行,每行两个整数fr,to,表示询问
    大树中结点 fr和 to之间的距离是多少。

    Output

      输出Q行,每行一个整数,第 i行是第 i个询问的答案。

    Sample Input

    5 2 3
    1 4
    1 3
    4 2
    4 5
    4 3
    3 2
    6 9
    1 8
    5 3

    Sample Output

    6
    3
    3

    HINT

    经过两次操作后,大树变成了下图所示的形状:



    结点6到9之间经过了6条边,所以距离为6;类似地,结点1到8之间经过了3条边;结点5到3之间也经过了3条边。

     
    题解:
    考场上想到了,但没时间拍了,结果只剩暴力分了……
    把大树缩成一棵新树,新树的每个节点是每个小子树的根,根与根之间连长度为大树上面的距离的边
    然后如果要求大树上两点的距离,则先将每个点跳到所在子树的根,然后再在新树上面跳,然后就是大量的细节了……
    code:
      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<cstring>
      5 #include<algorithm>
      6 using namespace std;
      7 typedef long long int64;
      8 char ch;
      9 bool ok;
     10 void read(int &x){
     11     ok=0;
     12     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
     13     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
     14     if (ok) x=-x;
     15 }
     16 void read(int64 &x){
     17     ok=0;
     18     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
     19     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
     20     if (ok) x=-x;
     21 }
     22 const int maxn=100000+5;
     23 const int maxm=maxn*2;
     24 int n,m,q,idx;
     25 int64 N,a,b,list[maxn];
     26 int root[maxn],from[maxn];
     27 struct Seg{
     28     int tot,siz[maxn*18],son[maxn*18][2],root[maxn];
     29     void insert(int &k,int p,int l,int r,int v){
     30         k=++tot,siz[k]=siz[p]+1;
     31         if (l==r) return;
     32         int m=(l+r)>>1;
     33         if (v<=m) son[k][1]=son[p][1],insert(son[k][0],son[p][0],l,m,v);
     34         else son[k][0]=son[p][0],insert(son[k][1],son[p][1],m+1,r,v);
     35     }
     36     void insert(int idx,int v){insert(root[idx],root[idx-1],1,n,v);}
     37     int calc(int x,int y,int k){
     38         x=root[x-1],y=root[y];
     39         int l=1,r=n,m;
     40         while (l<r){
     41             m=(l+r)>>1;
     42             if (siz[son[y][0]]-siz[son[x][0]]>=k) r=m,y=son[y][0],x=son[x][0];
     43             else l=m+1,k-=siz[son[y][0]]-siz[son[x][0]],y=son[y][1],x=son[x][1];
     44         }
     45         return l;
     46     }
     47 }T;
     48 int dfn[maxn],last[maxn],siz[maxn];
     49 struct Graph2{
     50     int tot,now[maxn],son[maxm],pre[maxm],fa[maxn][18],dep[maxn];
     51     int64 val[maxm],dis[maxn];
     52     void put(int a,int b,int64 c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
     53     void add(int a,int b,int64 c){put(a,b,c),put(b,a,c);}
     54     void dfs(int u){
     55         for (int i=0;fa[u][i];i++) fa[u][i+1]=fa[fa[u][i]][i];
     56         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) if (v!=fa[u][0])
     57             fa[v][0]=u,dep[v]=dep[u]+1,dis[v]=dis[u]+val[p],dfs(v);
     58     }
     59     void dfs2(int u){
     60         siz[u]=1,dfn[u]=++idx,T.insert(idx,u);
     61         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) if (v!=fa[u][0]) dfs2(v),siz[u]+=siz[v];
     62         last[u]=idx;
     63     }
     64     void prepare(){dfs(1),dfs2(1);}
     65     void swim(int &u,int h){for (int i=17;h;i--) if (h>=(1<<i)) h-=(1<<i),u=fa[u][i];}
     66     int get_lca(int u,int v){
     67         if (dep[u]<dep[v]) swap(u,v);
     68         swim(u,dep[u]-dep[v]);
     69         if (u==v) return u;
     70         for (int i=17;i>=0;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
     71         return fa[u][0];
     72     }
     73     int64 get_dist(int u,int v){return dis[u]+dis[v]-2*dis[get_lca(u,v)];}
     74     int find(int u,int v){
     75         swim(u,dep[u]-dep[v]-1);
     76         return u;   
     77     }
     78 }G[2];
     79 int calc(int64 x){return lower_bound(list+1,list+idx+1,x)-list;}
     80 int main(){
     81     read(n),read(m),read(q);
     82     for (int i=1;i<n;i++) read(a),read(b),G[0].add(a,b,1);
     83     G[0].prepare(),N=n,idx=1,root[1]=1,list[1]=N;
     84     for (int i=1;i<=m;i++){
     85         read(a),read(b);
     86         int t=calc(b),r=root[t],bb=T.calc(dfn[r],last[r],b-list[t-1]);
     87         G[1].add(idx+1,t,G[0].dis[bb]-G[0].dis[r]+1);
     88         N+=siz[a],list[++idx]=N,root[idx]=a,from[idx]=bb;
     89     }
     90     G[1].dfs(1);
     91     for (int i=1;i<=q;i++){
     92         read(a),read(b);
     93         int ta=calc(a),ra=root[ta],aa=T.calc(dfn[ra],last[ra],a-list[ta-1]);
     94         int tb=calc(b),rb=root[tb],bb=T.calc(dfn[rb],last[rb],b-list[tb-1]);
     95         int lca=G[1].get_lca(ta,tb);
     96         int64 res=G[0].dis[aa]-G[0].dis[ra]+G[0].dis[bb]-G[0].dis[rb]+G[1].get_dist(ta,tb);
     97         if (ta==tb) printf("%lld
    ",G[0].get_dist(aa,bb));
     98         else if (ta==lca){
     99             int frb=from[G[1].find(tb,lca)];
    100             printf("%lld
    ",res-(G[0].dis[aa]+G[0].dis[frb]-G[0].get_dist(aa,frb)-2*G[0].dis[ra]));
    101         }
    102         else if (tb==lca){
    103             int fra=from[G[1].find(ta,lca)];
    104             printf("%lld
    ",res-(G[0].dis[bb]+G[0].dis[fra]-G[0].get_dist(bb,fra)-2*G[0].dis[rb]));
    105         }
    106         else{
    107             int fra=from[G[1].find(ta,lca)];
    108             int frb=from[G[1].find(tb,lca)];
    109             printf("%lld
    ",res-(G[0].dis[fra]+G[0].dis[frb]-G[0].get_dist(fra,frb)-2*G[0].dis[root[lca]]));
    110         }
    111     }
    112     return 0;
    113 }
  • 相关阅读:
    数据库基础
    (转)数据流图
    (转)SQL执行顺序
    (转)数据库隔离级别及实现原理
    (转)求单链表是否有环,环入口和环长
    (转)最长公共子序列
    (转)Java锁、自旋锁、CAS机制
    Java线程状态转换
    OpenSUSE 13.2安装Texlive2014+Texmaker+Lyx
    GIMP也疯狂之动态图的制作(四)
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5407638.html
Copyright © 2011-2022 走看看