zoukankan      html  css  js  c++  java
  • [BZOJ4539][HNOI2016]树(主席树)

    4539: [Hnoi2016]树

    Time Limit: 40 Sec  Memory Limit: 256 MB
    Submit: 746  Solved: 292
    [Submit][Status][Discuss]

    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之间的距离是多少。N,M,Q<=100000

    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条边。

    Source

    思维难度低,代码难度高。

    直接上主席树即可。

    代码用时:0.5h。抄一次代码,错误率还是比较低的,只有一个地方接口参数写反了。

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<iostream>
      4 #define rep(i,l,r) for (int i=l; i<=r; i++)
      5 typedef long long ll;
      6 using namespace std;
      7 
      8 const int N=100100,M=2000100;
      9 int n,m,tot,dfn,sm[M],ls[M],rs[M],rt[N],lf[N],rg[N],id[N];
     10 struct P{ int id,rt,fa; ll l,r; }a[N];
     11 
     12 template<typename T>inline void rd(T &x){
     13    int t; char ch;
     14    for (t=0; !isdigit(ch=getchar()); t=(ch=='-'));
     15    for (x=ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0');
     16    if (t) x=-x;
     17 }
     18 
     19 void ins(int x,int &y,int L,int R,int k){
     20    y=++tot; sm[y]=sm[x]+1;
     21    if (L==R) return; int mid=(L+R)>>1;
     22    if (k<=mid) rs[y]=rs[x],ins(ls[x],ls[y],L,mid,k);
     23       else ls[y]=ls[x],ins(rs[x],rs[y],mid+1,R,k);
     24 }
     25 
     26 int que(int k,int z){
     27    int L=1,R=n,mid,t,x=rt[lf[k]-1],y=rt[rg[k]];
     28    while (L<R){
     29       mid=(L+R)>>1; t=sm[ls[y]]-sm[ls[x]];
     30       if (z<=t) R=mid,x=ls[x],y=ls[y];
     31          else L=mid+1,z-=t,x=rs[x],y=rs[y];
     32    }
     33    return L;
     34 }
     35 
     36 int getid(ll x,int ed){
     37    int L=1,R=ed+1,mid;
     38    while (L+1<R){
     39       mid=(L+R)>>1;
     40       if (a[mid].l<=x) L=mid; else R=mid;
     41    }
     42    return L;
     43 }
     44 
     45 struct T{
     46    int tot,fst[N],pnt[N<<1],len[N<<1],nxt[N<<1];
     47    int fa[N],sz[N],son[N],anc[N];
     48    ll d[N];
     49    void add(int x,int y,int z)
     50    { pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot; }
     51    
     52    void dfs(int x){
     53       int p; sz[x]=1;
     54       for (p=fst[x]; p; p=nxt[p]){
     55          int y=pnt[p];
     56          if (y!=fa[x]){
     57             fa[y]=x; d[y]=d[x]+len[p];
     58             dfs(y); sz[x]+=sz[y];
     59             if (sz[y]>sz[son[x]]) son[x]=y;
     60          }
     61       }
     62    }
     63    
     64    void nbr(int x,int tp){
     65       lf[x]=rg[x]=++dfn; id[dfn]=x; anc[x]=tp; int p;
     66       if (son[x]) nbr(son[x],tp),rg[x]=rg[son[x]];
     67       for (p=fst[x]; p; p=nxt[p]){
     68          int y=pnt[p];
     69          if (y!=fa[x] && y!=son[x]) nbr(y,y),rg[x]=rg[y];
     70       }
     71    }
     72    
     73    void div(int x,int tp){
     74       anc[x]=tp; int p;
     75       if (son[x]) div(son[x],tp);
     76       for (p=fst[x]; p; p=nxt[p]){
     77          int y=pnt[p];
     78          if (y!=fa[x] && y!=son[x]) div(y,y);
     79       }
     80    }
     81    
     82    int lca(int x,int y){
     83       for (; anc[x]!=anc[y]; x=fa[anc[x]])
     84          if (d[anc[x]]<d[anc[y]]) swap(x,y);
     85       return (d[x]<d[y]) ? x : y;
     86    }
     87    
     88    int gettp(int x,int y){
     89       int z;
     90       for (; anc[x]!=anc[y]; x=fa[anc[x]]) z=anc[x];
     91       return (x==y) ? z : son[y];
     92    }
     93    
     94    void build(){
     95       rep(i,1,n) ins(1,n,rt[i-1],rt[i],id[i]);
     96    }
     97    
     98    ll dist(int x,int y){ return d[x]+d[y]-(d[lca(x,y)]<<1); }
     99 }t1,t2;
    100 
    101 int main(){
    102    freopen("bzoj4539.in","r",stdin);
    103    freopen("bzoj4539.out","w",stdout);
    104    rd(n); rd(m); int cas,z; ll x,y;
    105    rd(cas);
    106    rep(i,1,n-1) rd(x),rd(y),t1.add(x,y,1),t1.add(y,x,1);
    107    t1.dfs(1); t1.nbr(1,1);
    108    rep(i,1,n) ins(rt[i-1],rt[i],1,n,id[i]);
    109    a[1].id=1; a[1].rt=1; a[1].l=1; a[1].r=n;
    110    rep(i,1,m){
    111       rd(x); rd(y);
    112       a[i+1].rt=x; a[i+1].id=i+1;
    113       a[i+1].l=a[i].r+1; a[i+1].r=a[i].r+t1.sz[x];
    114       z=getid(y,i); a[i+1].fa=y=que(a[z].rt,y-a[z].l+1);
    115       t2.add(z,i+1,t1.d[y]-t1.d[a[z].rt]+1);
    116    }
    117    t2.dfs(1); t2.div(1,1); int u,v,w; ll ans;
    118    while (cas--){
    119       rd(x); rd(y); u=getid(x,m+1); v=getid(y,m+1); w=t2.lca(u,v);
    120       x=que(a[u].rt,x-a[u].l+1); y=que(a[v].rt,y-a[v].l+1);
    121       if (u==v) printf("%lld
    ",t1.dist(x,y));
    122       else{
    123          if (u==w) swap(u,v),swap(x,y);
    124          if (v==w){
    125             v=t2.gettp(u,w);
    126             ans=t1.d[x]-t1.d[a[u].rt]+t2.d[u]-t2.d[v];
    127             x=a[v].fa; ans+=t1.dist(x,y)+1;
    128          }else{
    129             ans=t1.d[x]-t1.d[a[u].rt]+t1.d[y]-t1.d[a[v].rt]+t2.dist(u,v);
    130             u=t2.gettp(u,w); v=t2.gettp(v,w);
    131             x=a[u].fa; y=a[v].fa;
    132             ans-=(t1.d[t1.lca(x,y)]-t1.d[a[w].rt])<<1;
    133          }
    134          printf("%lld
    ",ans);
    135       }
    136    }
    137    return 0;
    138 }

     

  • 相关阅读:
    Android学习笔记(四十):Preference的使用
    怎样在小方框上打对号 小方框内打对勾 word 方框打对勾
    PreTranslateMessage作用和用法
    MyBatis与Spring设置callSettersOnNulls
    EJB3.0开发环境的搭建
    经常使用虚拟现实仿真软件总汇(zz)
    slf自己主动绑定实现类过程推断
    DLNA介绍(包含UPnP,2011/6/20 更新)
    从技术到管理的问题
    NOI第一天感想&小结
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8318861.html
Copyright © 2011-2022 走看看