• 树链剖分


    #树链剖分

    1,将树从x到y结点最短路径上所有节点的值都加上z

    这也是个模板题了吧

    我们很容易想到,树上差分可以以O(n+m)的优秀复杂度解决这个问题

    2,求树从x到y结点最短路径上所有节点的值之和

    lca大水题,我们又很容易地想到,dfs O(n)预处理每个节点的dis(即到根节点的最短路径长度)

    dis(到根节点最短路径长度)

    lca性质:树上两点最短距离=dis(x)+dis(y)-2*dis(lca) O(mlogn+n)

    树链剖分 就是对一棵树分成几条链,把树形变为线性,减少处理难度

    需要处理的问题:

    • 将树从x到y结点最短路径上所有节点的值都加上z
    • 求树从x到y结点最短路径上所有节点的值之和
    • 将以x为根节点的子树内所有节点值都加上z
    • 求以x为根节点的子树内所有节点值之和

    概念://可以先看代码再一一理解

    • 重儿子:对于每一个非叶子节点,它的所有儿子中 儿子数量最多的那一个儿子 为该节点的重儿子

    • 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子

    • 叶子节点没有重儿子也没有轻儿子(因为它没有儿子。。)非叶节点有且只有1个重儿子

    • 重边:连接父亲节点与重儿子的边叫做重边

    • 轻边:剩下的即为轻边

    • 重链:相邻重边连起来的的路径叫重链

    • 轻链:轻边连的路径

    • 对于叶子节点,若其为轻儿子,则有一条以自己为起点的长度为1的链

      变量声明:

      (fa[i]~i的爸爸,d[i]~i的深度,siz[i]i为根的子树节点个数,wson[i]保存重儿子,rk[i]保存当前dfs标号在树中对应节点)

      (top[i]当前节点所在链顶端节点,id[i]~dfs执行顺序(剖分后新编号))

      两遍dfs

    dfs1():

    处理出siz和son数组(如果一个点多个儿子子树相等且最大,随便找一个当重儿子)

    顺便记录点的父亲和深度,处理fa和d数组,手动模拟一下吧

    inline void dfs1(int x,int fa,int deep){
    	dep[x] = deep;//标记每个点深度
    	fa[x] = fa;
    	siz[x] = 1;//标记每个非叶子节点的子树大小,包含他自己
    	//int maxson = -1;//记录重儿子个数
    	for(int i = head[x];i;i=edge[i].next){
    	int y = edge[i].to;
    	if(y == fa) continue;
    	dfs1(y,x,deep+1);
    	siz[x] += siz[y];	//son的siz已被处理,更新fa的siz
    	if(siz[y] > siz[wson[x]]) wson[u]=y;//选最大siz
    	}
    }
    

    dfs2():

    连接重链,标记每个点的dfs序,为了用数据结构维护重链,dfs时保证一条重链各个节点dfs序连续

    即处理出top,id,rk

    void dfs2(int u,int t){//t重链顶端
    	top[u] = t;//
    	id[u]=cnt++; //标记dfs序
    	rk[cnt] = u;//序号cnt对应节点v
    	if(!wson[u]) return;
    	dfs2(wson[u],t);
    	//优先选择进入重儿子来保证一条重链上各个节点dfs序连续
    	//一个点和它的重儿子处于一条同一重链,所以重儿子顶端还是t
    	for(int i=head[u];i;i=e[i].next){
    		int v = e[i].to;
            if(v != wson[u] && v!=fa[u]) dfs2(v,v);//一个点位于链低端,那么它的top必然是它本身
    	}
    }
    

    为什么是dfs2(v,v)呢,因为当v是重儿子的时候,它不可能为一条链的顶,因为根据重边的定义,一定有一条边连向重儿子,若重儿子为顶,还会有一条边连向它,所以重儿子不会为顶端。

    然后统计答案,中间一定需要别的数据结构

    例题和代码就不放了,洛谷上有很多

    pshttps://www.cnblogs.com/lykkk/p/10183778.html#autoid-3-0-0 这篇文章写的也很好
    PS 一定要多写写,最好一周写一两道,要不然很容易bug

  • 相关阅读:
    获取ios设备的当前IP地址
    swift 日期的基本操作
    iOS ChildViewController使用示例
    Swift 进制转换问题
    objc_msgSend iOS8 EXC_BAD_ACCESS
    objc非主流代码技巧
    黑魔法__attribute__((cleanup))
    判断一个对象是否实现了某方法,而非继承而来
    Controlling How NSThread and NSRunLoop Exit
    万年历-农历-节气
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13369947.html
Copyright © 2020-2023  润新知