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之间的距离是多少。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条边。

    正解:dfs序主席树+lca

    恶心数据结构题+码农题。。前后总共调了6个多小时。。WA显示成RE也无语至极。。

    来自ljh2000大神犇的题解:

    具体做法:

      首先对于模板树进行预处理,dfs一遍得到dfs序,为了维护子树第k小编号的查询操作,构主席树。

      (ps:在主席树上查找子树第k小编号是一个经典问题,按照dfs序依次把每个编号相应的位置+1,然后就是常规的区间第k小问题)

      对于复制操作,复制操作的话对于每次复制我只需要记录这次复制的这棵子树的根,根接到了哪个点的下方,当然上述记录的都是在原树中的相应编号。同时为了方便之后计算这棵子树内到根的距离,不妨记录一下根在原树到1的距离,这样以来当我想查询这棵子树内的某个点到根的距离时,直接用在原树中与1的距离之差即可。

      对于最后的查询操作,需要仔细考虑了,有很多细节。当x和y处在同一块中(也就是新树的同一结点上时),直接查询。否则,先求出在x、y各自所处的块(也就是新树上的两个结点,不妨设为Rx、Ry,且deep[Ry]<deep[Rx])在新树上的lca,如果Ry=lca,则不用处理;否则就把x、y先跳到所在的块的顶端,记录贡献,再一直跳到lca的儿子结点(实际上就是儿子结点所表示的块中的根结点),接着往上走一步即可进入lca的块中。对于同一块中的直接查询即可。细节的话太多不赘述了,最重要的一点就是因为最大情况下,点数肯定是超int的,所以最好是都开longlong。

      1 //It is made by wfj_2048~
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <cstring>
      5 #include <cstdlib>
      6 #include <cstdio>
      7 #include <vector>
      8 #include <cmath>
      9 #include <queue>
     10 #include <stack>
     11 #include <map>
     12 #include <set>
     13 #define N (100010)
     14 #define il inline
     15 #define RG register
     16 #define ll long long
     17 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
     18 
     19 using namespace std;
     20 
     21 il ll gll(){
     22     ll x=0,q=1; char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
     23     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
     24 }
     25 
     26 struct edge{ ll nt,to,dis; };
     27 
     28 struct tree{
     29     ll head[N],dfn[N],tid[N],dis[N],id[N],anc[N],up[N],size[N],top[N],fa[N],son[N],dep[N],n,num,cnt,tot;
     30     edge g[2*N];
     31     
     32     il void insert(ll from,ll to,ll dis){ g[++num]=(edge){head[from],to,dis},head[from]=num; return; }
     33     
     34     il void dfs1(ll x,ll p){
     35     dep[x]=dep[p]+1,fa[x]=p,size[x]=1; ll mx=0,v;
     36     for (RG ll i=head[x];i;i=g[i].nt){
     37         v=g[i].to; if (v==p) continue;
     38         dis[v]=dis[x]+g[i].dis; dfs1(v,x);
     39         size[x]+=size[v]; if (size[mx]<=size[v]) mx=v;
     40     }
     41     son[x]=mx; return;
     42     }
     43     
     44     il void dfs2(ll x,ll p,ll a){
     45     dfn[++cnt]=x,tid[x]=cnt,top[x]=a;
     46     if (son[x]) dfs2(son[x],x,a); ll v;
     47     for (RG ll i=head[x];i;i=g[i].nt){
     48         v=g[i].to; if (v==p || v==son[x]) continue;
     49         dfs2(v,x,v);
     50     }
     51     return;
     52     }
     53     
     54     il ll lca(ll u,ll v){
     55     while (top[u]!=top[v]){
     56         if (dep[top[u]]<dep[top[v]]) swap(u,v);
     57         u=fa[top[u]];
     58     }
     59     return dep[u]>dep[v] ? v : u;
     60     }
     61     
     62     il ll jump(ll u,ll v){
     63     ll x=u; while (top[u]!=top[v]) x=top[u],u=fa[top[u]];
     64     return u==v ? x : son[v];
     65     }
     66     
     67 }tr1,tr2;
     68 
     69 struct chairtree{
     70     ll root[N],sum[20*N],ls[20*N],rs[20*N],sz;
     71     
     72     il void build(ll x,ll &y,ll l,ll r,ll v){
     73     sum[y=++sz]=sum[x]+1,ls[y]=ls[x],rs[y]=rs[x];
     74     if (l==r) return; ll mid=(l+r)>>1;
     75     if (v<=mid) build(ls[x],ls[y],l,mid,v);
     76     else build(rs[x],rs[y],mid+1,r,v);
     77     return;
     78     }
     79     
     80     il ll query(ll x,ll y,ll l,ll r,ll k){
     81     if (l==r) return l; ll mid=(l+r)>>1;
     82     if (k<=sum[ls[y]]-sum[ls[x]]) return query(ls[x],ls[y],l,mid,k);
     83     else return query(rs[x],rs[y],mid+1,r,k-sum[ls[y]]+sum[ls[x]]);
     84     }
     85     
     86 }ch;
     87 
     88 il ll find(ll x){
     89     if (x<=tr1.n) return 1;
     90     ll l=1,r=tr2.n,mid,ans=1;
     91     while (l<=r){
     92     mid=(l+r)>>1;
     93     if (x<tr2.id[mid]) r=mid-1;
     94     else ans=mid,l=mid+1;
     95     }
     96     return ans;
     97 }
     98 
     99 il ll query(ll blv,ll v){
    100     if (v<=tr1.n) return v; v-=tr2.id[blv]-1;
    101     ll x=tr2.anc[blv],l=tr1.tid[x],r=l+tr1.size[x]-1;
    102     return ch.query(ch.root[l-1],ch.root[r],1,tr1.n,v);
    103 }
    104 
    105 il void work(){
    106     tr1.n=gll(); ll m=gll(),q=gll();
    107     for (RG ll i=1;i<tr1.n;++i){ ll u=gll(),v=gll(); tr1.insert(u,v,1),tr1.insert(v,u,1); }
    108     tr1.dfs1(1,0),tr1.dfs2(1,0,1); tr2.id[1]=1,tr2.anc[1]=1,tr2.n=1,tr2.tot=tr1.n;
    109     for (RG ll i=1;i<=tr1.n;++i) ch.build(ch.root[i-1],ch.root[i],1,tr1.n,tr1.dfn[i]);
    110     for (RG ll i=1;i<=m;++i){
    111     ll u=gll(),v=gll(),blv=find(v),idv=query(blv,v);
    112     tr2.n++,tr2.id[tr2.n]=tr2.tot+1,tr2.tot+=tr1.size[u],tr2.anc[tr2.n]=u,tr2.up[tr2.n]=idv;
    113     tr2.insert(blv,tr2.n,tr1.dis[idv]-tr1.dis[tr2.anc[blv]]+1);
    114     }
    115     tr2.dfs1(1,0),tr2.dfs2(1,0,1);
    116     for (RG ll i=1;i<=q;++i){
    117     ll u=gll(),v=gll(),blu=find(u),blv=find(v);
    118     ll idu=query(blu,u),idv=query(blv,v),lca,ans=0;
    119     if (blu==blv){
    120         lca=tr1.lca(idu,idv);
    121         ans=tr1.dis[idu]+tr1.dis[idv]-2*tr1.dis[lca];
    122         printf("%lld
    ",ans); continue;
    123     }
    124     if (tr2.dep[blu]>tr2.dep[blv]) swap(u,v),swap(blu,blv),swap(idu,idv);
    125     lca=tr2.lca(blu,blv);
    126     if (blu!=lca){
    127         ans=tr1.dis[idu]-tr1.dis[tr2.anc[blu]];
    128         u=tr2.jump(blu,lca); ans+=tr2.dis[blu]-tr2.dis[u]+1;
    129         u=tr2.up[u];
    130     }else u=query(blu,u);
    131     ans+=tr1.dis[idv]-tr1.dis[tr2.anc[blv]];
    132     v=tr2.jump(blv,lca); ans+=tr2.dis[blv]-tr2.dis[v]+1;
    133     v=tr2.up[v],lca=tr1.lca(u,v);
    134     ans+=tr1.dis[u]+tr1.dis[v]-2*tr1.dis[lca];
    135     printf("%lld
    ",ans);
    136     }
    137     return;
    138 }
    139 
    140 int main(){
    141     File("tree");
    142     work();
    143     return 0;
    144 }
    145 //鬼畜dfs序+主席树+lca沃日
  • 相关阅读:
    Java实现 LeetCode 382 链表随机节点
    Java实现 LeetCode 382 链表随机节点
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
    Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
    Linux下的iwpriv(iwlist、iwconfig)的简单应用
    OCX控件的注册卸载,以及判断是否注册
    .OCX、.dll文件注册命令Regsvr32的使用
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6416591.html
Copyright © 2011-2022 走看看