• 树链剖分


    树链剖分的实质:将一棵树划分成若干条链,用数据结构去维护每条链。

      如:把边或点哈希到线段树(或其他数据结构)上进行维护和查询。

    这样做的理由:从根到某一点的路径上,不超过logn条轻边和不超过logn条重路径。

    下面开始介绍树链剖分的做法:

      size(u)为以u为根的子树节点个数(包括u),令v为u的儿子中size值最大的节点,那么(u,v)就是重边,其余边为轻边。

      Ps:从u开始走向儿子的重边只有一条!所以有多个size值最大儿子时,选其中一个即可。

      所以有下性质:

        1.轻边(U,V),size(V)<=size(U)/2。

        2.从根到某一点的路径上,不超过O(logN)条轻边,不超过O(logN)条重路径。

      这个两个性质是树链剖分树链操作的时间复杂度的保证。

     树链剖分所需要维护的信息:

      sz[x]:以x为根节点的节点数(包括x)

      fa[x]:x的父亲节点

      deep[x]:x的深度

      son[x]:x的重儿子

      top[x]:x所在链的顶端节点

      id[x]:点x树链剖分后在线段树上的位置

      hid[x]:线段树上位置为x的点在树上的位置(与id[x]为逆运算)

    树链剖分具体过程:

      第一遍dfs:求出sz,fa,deep,son数组。

      第二遍dfs:求出top,id,hid数组。

    然后是边权或点权信息的维护:

      修改x到y的路径上的信息:

        (1)如果u与v在同一条重链上,直接修改即可

        (2)如果u与v不在同一条重链上,那么就一边进行修改,一边将u与v往同一条重链上靠,之后转化成第一种情况。

      查询x到y路径上的信息同理。

    Ps: 当处理边权时,每条边在线段树上的位置,由深度大的节点的id值表示。

      当处理点权时,每个点在线段树上的位置,由该点的id值表示。

    然后。。。。没有然后了。。

    模板:

     1 vector<int>mp[K];
     2 int top[K],sz[K],fa[K],son[K],id[K],hid[K],deep[K];
     3 int cnt,add[4*K];
     4 
     5 int query(int o,int l,int r,int x)
     6 {
     7     if(l==r)    return add[o];
     8     int mid=l+r>>1;
     9     if(x<=mid) return query(o<<1,l,mid,x)+add[o];
    10     return query(o<<1|1,mid+1,r,x)+add[o];
    11 }
    12 int update(int o,int l,int r,int nl,int nr,int v)
    13 {
    14     if(l==nl&&r==nr)
    15        return add[o]+=v;
    16     int mid=l+r>>1;
    17     if(nr<=mid) update(o<<1,l,mid,nl,nr,v);
    18     else if(nl>mid) update(o<<1|1,mid+1,r,nl,nr,v);
    19     else update(o<<1,l,mid,nl,mid,v),update(o<<1|1,mid+1,r,mid+1,nr,v);
    20 }
    21 void dfs1(int x,int f)
    22 {
    23     sz[x]=1,fa[x]=f,son[x]=-1,deep[x]=deep[f]+1;
    24     for(int i=0;i<mp[x].size();i++)
    25     if(mp[x][i]!=f)
    26     {
    27         dfs1(mp[x][i],x);
    28         sz[x]+=sz[mp[x][i]];
    29         if(son[x]==-1||sz[son[x]]<sz[mp[x][i]])
    30             son[x]=mp[x][i];
    31     }
    32 }
    33 void dfs2(int x,int f)  ///每条边用深度大的节点的序号表示
    34 {
    35     top[x]=f,id[x]=++cnt,hid[id[x]]=x;
    36     if(son[x]!=-1) dfs2(son[x],f);
    37     for(int i=0;i<mp[x].size();i++)
    38     if(mp[x][i]!=fa[x]&&mp[x][i]!=son[x])
    39         dfs2(mp[x][i],mp[x][i]);
    40 }
    41 void tree_update(int x,int y,int v)
    42 {
    43     while(top[x]!=top[y])
    44     {
    45         if(deep[top[x]]<deep[top[y]]) swap(x,y);
    46         update(1,1,cnt,id[top[x]],id[x],v);//更新x-top[x]-fa[top[x]]
    47         x=fa[top[x]];//所以直接fa[top[x]]
    48     }
    49     if(x==y) return;//点修改请注释这句
    50     if(deep[x]>deep[y]) swap(x,y);
    51     update(1,1,cnt,id[son[x]],id[y],v);//点修改请改为id[x]
    52 }
  • 相关阅读:
    对于大流量的网站,您采用什么样的方法来解决访问量问题?
    div section article区分--20150227
    不懂的code整理学习
    常用又容易忘记的代码
    【转】机器学习中常用损失函数
    姿态估计的两个数据集COCO和MPII的认识
    用caffe训练openpose过程中,出现异常
    编译caffe的诸多注意事项
    Win7下Anaconda3+Tensorflow
    论文阅读(Zhe Cao——【CVPR2017】Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields )
  • 原文地址:https://www.cnblogs.com/weeping/p/6869449.html
Copyright © 2020-2023  润新知