树链剖分总结

题目

luoguP2146 [NOI2015]软件包管理器
luoguP2590 [ZJOI2008]树的统计
luoguP3038 [USACO11DEC]牧草种植Grass Planting
luoguP3178 [HAOI2015]树上操作
luoguP3258 [JLOI2014]松鼠的新家
luoguP3833 [SHOI2012]魔法树
luoguP3950 部落冲突

题解

软件包管理器
牧草种植
树上操作
松鼠的新家
魔法树
部落冲突

核心代码

dfs1

//第一次dfs维护出fa,dep,siz,son四个数组
//fa[u]:u的父节点,dep[u]:u的深度,这个变量后面在修改链上信息时会用到
//siz[u]:u的子树大小(包括u),son[u]:u的重儿子(重链剖分)
void dfs1(int u,int f){
    fa[u]=f;dep[u]=dep[f]+1;siz[u]=1;son[u]=0;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].e;
        if(v==f)continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        son[u]=((siz[v]>siz[son[u]])?v:son[u]);
    }
}

dfs2

//第二个dfs维护出seg,rev,top三个数组
//dfs(u)维护出u的子树的相关标记,这就意味着要在调用函数之前给起始(根)节点赋值
//seg[u]:点u在剖分后区间的位置,seg[0]被用作计数变量,记录区间中点的个数
//rev[u]:区间中第u个位置存放的点
//top[u]:点u所在重链的链头
void dfs2(int u,int f){
    if(son[u]){//一定要先维护重儿子的标记,使得在线段树区间内重链连续排列
        seg[son[u]]=++seg[0];
        rev[seg[0]]=son[u];
        top[son[u]]=top[u];
        dfs2(son[u],u);
    }
    for(int i=head[u];i!=-1;i=edge[i].nxt){//维护完重儿子后再维护轻儿子
        int v=edge[i].e;
        if(!top[v]){//排除掉重儿子和父节点
            seg[v]=++seg[0];
            rev[seg[0]]=v;
            top[v]=v;
            dfs2(v,u);
        }
    }
}

树剖支持的相关操作

  • 树上链信息的维护
  • 树上子树信息的维护
  • 未完待续…

对树剖的一点理解

两个字,哈希
即,利用某些数据结构(线段树,Splay……)处理区间问题的优势来处理树上的信息处理问题,具体做法就是按照某些规则(如轻重链剖分,长短链剖分……)将树分成有规律的几块放在一个区间里,然后用合适的数据结构去处理。

T o B e C o n t i n u e . . . To Be Continue... ToBeContinue...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值