• 树链剖分


    树链剖分

    树链剖分就是将一棵点权树以先遍历重儿子的方式,得到一个dfs序,再对这个dfs序进行操作,与一般的dfs序不同,重链在该dfs序是一个连续不断的区间,该dfs序支持链修改,链查询,子树查询,子树修改,求lca等。在一棵有根树上,我们称一个节点u 的子节点v 为节点u 的重儿子当且仅当v 是所有子节点中大小最大的(如果有多个,则随便选定一个),其余节点称为轻儿子。如果我们对于所有内部节点(有儿子的节点)都选择一个节点作为其重儿子,那么我们就得到了一个轻重链划分,我们称连接节点及其重儿子的边为重边,反之则为轻边,一条由重边组成的链称为重链

    要定义的的东西:

    father[ N ]  :表示一个节点的父亲节点;

    in[ N ] :表示一个节点进dfs序的位置;

    out[  N ] :表示一个节点出dfs序的位置;

    top[ N  ] :表示一个节点只走重链能到达的最高位置;

    son [ N  ] :表示一个节点的重儿子;

    siz[ N ] :表示一个节点的大小(其子树中节点数加上自己);

    dep[ N ] :表示一个节点的深度;

    代码:

     

    void dfs1( int u ) {
    siz[u] = 1;
    for( int t = head[u]; t; t = last[t] ) {
    int v = dest[t];
    if( v == fat[u] ) continue;
    fat[v] = u;
    dep[v] = dep[u]+1;
    dfs(v);
    siz[u] += siz[v];
    if( siz[v] > siz[son[u]] ) son[u] = v;
    }
    }
    dep[1] = 1;
    fat[1] = 1;
    dfs1(1);

     

    void dfs2( int u, int tp ) {
    in[u] = ++idc;
    top[u] = tp;
    if( son[u] ) dfs2( son[u], tp );//遍历重链
    for( int t = head[u]; t; t = last[t] ) {//遍历轻边
    int v = dest[t];
    if( v == fat[u] || v == son[u] ) continue;
    dfs2( v, v );
    }
    }
    idc = 0;
    dfs2(1,1);

    求lca:

    int lca( int u, int v ) {
    while( top[u] != top[v] ) {
    if( dep[top[u]] < dep[top[v]] ) swap(u,v);
    u = fat[top[u]];
    }
    return dep[u] < dep[v] ? u : v;
    }

     

  • 相关阅读:
    [SDOI2015] 序列统计
    [BZOJ3514] Codechef MARCH14 GERALD07加强版
    [CF1082E] Increasing Frequency
    [CF1093G] Multidimensional Queries
    [HNOI2013] 切糕
    [HEOI2017] 寿司餐厅 + 最大权闭合子图的总结
    [BZOJ3771] Triple
    [HEOI2016] 字符串
    [总结] 后缀数组学习笔记
    [Luogu 3613] 睡觉困难综合征
  • 原文地址:https://www.cnblogs.com/ganster/p/8429967.html
Copyright © 2020-2023  润新知