蒟蒻浅谈树链剖分之一——两个dfs操作

树链剖分,顾名思义就是将树形的结构剖分成链,我们以此便于在链上操作

首先我们需要明白在树链剖分中的一些概念

重儿子:某节点所有儿子中子树最多的儿子

重链:有重儿子构成的链

dfs序:按重儿子优先遍历时的顺序

轻儿子的意思就与重儿子相反

首先是第一个dfs操作

在本次操作中,我们主要做的是处理所有节点的父亲,子树大小,重儿子,深度等操作

void dfs1(int now,int father,int deep)
{
    tree[now].depth=deep;//初始化当前节点的深度,子树大小,父亲
    tree[now].size=1;
    tree[now].fa=father;
    maxson=-1;
    for(int i=head[now];i;i=tree[i].next)
    {
        int v=tree[now].to;
        if(v==tree[now].father)//因为练的是双向边,所以不免会练到自己的父亲节点,就跳过
        {
            continue;
        }
        dfs(v,now,deep+1);
        tree[now].size+=tree[v].size;//累加子树的大小
        if(tree[v].size>maxson)
        {
            tree[now].son=v;
            maxson=size[v];
        }
    }
} 

接下来就是第二次dfs操作,将树剖分成链的过程

我们在这时就有一个非常重要的东西那就是dfs序

dfs序就是我们遍历时的顺序,在这里的遍历方式是二叉树的中序遍历

因为我们在树链剖分中是以重儿子优先

所以dfs序可能会与实际有出入

所以我们还需新开一个数组来维护新的dfs序

以便于我们的线段树操作

但蒟蒻太弱,以后再来讲套线段树的事情

我们先好好的剖分吧

void dfs2(int now,int topf)//从当前节点开始,topf为当前链的顶端
{
    tree[now].index=++TIME;//dfs序
    w[tree[now].index]=tree[now].value;//维护
    tree[now].top=topf;//初始化,链顶即为topf
    if(!tree[now].son)//没有重儿子就先不用便利了
    {
        return;
    }
    dfs(tree[now].son,topf);//优先遍历重儿子
    for(int i=head[now];i;i=tree[i].next)//在处理其他的情况
    {
        int v=tree[i].to;
        if(v==father||v==tree[now].son)//不能为自己的父亲节点,也不能为重儿子
        {
            continue;
        }
        dfs(v,v);//在轻儿子那里新开一条链
    }
} 

所以说两个dfs还是比较好理解的

关键的是在树链剖分里更好的套数据结构

欲知后事如何,请听下回分解!

原文地址:https://www.cnblogs.com/LJB666/p/10540244.html

时间: 2024-10-14 04:26:01

蒟蒻浅谈树链剖分之一——两个dfs操作的相关文章

浅谈树链剖分

今天刚学会树剖......(是不是觉得我很菜QwQ) 树剖的用处: 引子问题1: 给你一颗树,支持两种操作: 1.给x到y路径上的值加z 2.求出点x的值 简单,树上差分嘛,前几天刚学过啊. 引子问题2: 给你一颗树,支持两种操作: 1.给以x为根的子树加z 2.求出以x为根的子树的和. 简单,dfs序+线段树啊. 那么把两个问题结合起来呢?——树链剖分华丽丽登场!!! 树剖核心思想: 听说线段树挺好用的,区改区查只要log的复杂度,但是只能在线性结构上用,哎,真是太遗憾了. 听说有一种叫做df

浅谈树链剖分(C++、算法、树结构)

关于数链剖分我在网上看到的有几个比较好的讲解,本篇主要是对AC代码的注释(感谢各位witer的提供) 这是讲解 http://www.cnblogs.com/kuangbin/archive/2013/08/15/3259083.html 另一个是百度文库 http://wenku.baidu.com/link?url=DY8CAbwdjitIiv8XQsHmVPi--dQAqw5z6dc_6N1Plh4u5Nfc1aCADQm4oAvt4Sqe1mXSixezzK4lRxofQKMX9cNzJ

树链剖分(从入门到入土。)

前置知识:线段树,链式前向星,LCA,DFS序 树链剖分通常的操作: 1.x -> y 的路径上修改 2.x -> y 的路径上查询 3. 对于 x 的子树修改 4.对于 x 的子树查询. 一般还有换根操作.树剖也也可以做LCA. 树链剖分有两个DFS 这两个DFS就是把一棵树变成一个序列. 然后就可以用数据结构来维护了. 第一个DFS 用来求 \(fa\)(祖先节点) \(size\)(子树大小)\(son\)(重儿子) \(d\)(深度) 重儿子指的是\(size\)较大的儿子节点. 第二

[总结]树链剖分的详细介绍

目录 一.关于树链剖分 二.树链剖分实现流程 二.树链剖分具体实现 1.需要表示的变量 2.储存一棵树 3.第一次遍历,处理fa,dep,size,son数组 4.第二次遍历,处理top,seg,rev数组 5.初始化线段树 6.单点修改 7.区间修改---以x为根结点的子树内节点的值都加val 8.区间修改---节点x到节点y的最短路径中同时加val 9.区间查询---以x为根结点的子树内节点的值的和 10.区间查询---节点x到节点y的最短路径中节点的和 11.区间查询---节点x到节点y的

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C

bzoj1036 count 树链剖分或LCT

这道题很久以前用树链剖分写的,最近在学LCT ,就用LCT再写了一遍,也有一些收获. 因为这道题点权可以是负数,所以在update时就要注意一下,因为平时我的0节点表示空,它的点权为0,这样可以处理点权为非负求最大值和求和的情况(即不用特判某个点是否有左右儿子,直接更新就行了),但这道题就不行(求和要求它为0,求最大值要求它为-oo).所以就必须特判~~~~ 综上:若0号节点存在一个不可能成为答案(在求最大值时是-oo,求最小值时是+oo)或对答案没有贡献的值(在求和时是0)时,初始化时将0节点

HDU 3966 (树链剖分+线段树)

Problem Aragorn's Story (HDU 3966) 题目大意 给定一颗树,有点权. 要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值. 解题分析 树链剖分模板题. 实质上树链剖分进行了点对点的一次映射,保证了重链上的点在线段树上的位置是连续的. 树链剖分的两个性质(转): 性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v]: 性质2:从根到某一点的路径上轻链.重链的个数都不大于logn. 保证了一个区间的时间复杂度是log2(n).

树链剖分 入门

什么是树链剖分? 树链剖分说白了就是将树的节点按照某种顺序编号,使其在特殊的链上编号连续(类似区间),方便用数据结构维护. 如何树链剖分? 树链剖分一般分为重链剖分和长链剖分,这里只介绍重链剖分(我也只会重链剖分). 重链剖分中有几个概念: 重儿子:一个节点的所有子节点中,以某个子节点为根的子树中节点数量最多的称为重儿子(如果最多的数量相同随便取一个). 轻儿子:一个节点的所有子节点中,不是重儿子的节点就是轻儿子(这不是废话吗). 重边:父节点与重儿子所连成的边. 轻边:父节点与轻儿子所连成的边

午学树链剖分有感~

今天上课谈到树链剖分,被机房某dalao嘲讽了一波,决定冒着不听课的风险学链剖 关于这篇blog的灵感来源:传送门,不妥删 1.0前置知识 1.1链式向前星 这个应该都会吧,但还是附上讲解,这个图很易懂啊,蒟蒻当时一直没学懂,看了图才发现自己有多弱智 1.2dfs序 这个学长上课讲的随便找了一个讲解,仅供参考:传送门 1.3线段树 线段树应该都学了,就不附连接了 1.4为什么要学链剖 小蒟蒻没怎么做过树上倍增和链剖的题,但据说树上倍增的题链剖都能做,但链剖的题树上倍增不一定能做 2.0正文 2.