树上差分 与 树链剖分

本文介绍了树上差分的概念,指出它在树结构中与线性问题的相似性,并提及树上差分是维护边的值。同时,文章详细阐述了树链剖分的原理,如何通过两次DFS找到重链和轻链,以实现高效地维护树上的前缀和与差分。树链剖分的时间复杂度为O(n * logn * logn)。虽然文中提到了例题,但未提供具体代码或解决方案。
摘要由CSDN通过智能技术生成

树上差分就是说;
其实树上的问题真的和线性的问题是很像的只不过是迭代方式发生了一个变化;
线性的前缀和:前缀和;
线性的差分:差分;
线性的这两个东西的结合:线段树;
在树上就分别是:
开一个数组表示这个节点的子树上的权值之和;
树上差分;
树链剖分;

第一个树上面的前缀和就不讲了,很简单;

来个树上差分;
首先我们要知道树上差分维护的是一条边的值;
倞阶指南上面有两幅图画的好;
每次求边的值的时候会把大半棵树遍历一遍;
在那条边的两个节点上打上+1的标记然后在LCA上打上-2的标记;

代码
int dfs(int u, int father)
{
   
    int res = d[u];
    //此处的D就是差分标记的数组;代表的是这个点跟他爸爸相连的边的权值;
    for (int i = h[u]; ~i; i = ne[i])
    {
   
        int j = e[i];
        if (j != father)
        {
   
            int s = dfs(j, u);
            res += s;
        }
    }
    return res;
}

树链剖分,就是说,一个区间里面,如果既要完成前缀和也要完成差分的功能的话那么就只能用线段树树状数组分块等方法,而在一个树上如果既要完成差分又要完成前缀和那么就应该用树链剖分和线段树;
线段树里面的每个点的u表示的是原来树上的一条边;

现在是主要内容,我们通过两次dfs求出各种前置的必要的信息,然后将对于每个节点,他的子树里面最大的那个就是重儿子,连接他和重儿子以及重儿子的儿子一直到底的那条边叫做重链;
重链的所有长度必然大于等于轻链的长度,这里运用了贪心选择的性质,不然的话我们就可以使用调整法来进行一个替换,然后第二次dfs的时候我们保证每次都先去遍历重儿子,然后第二次dfs遍历出来的顺序就是线段树里面的真实顺序,然后这样子我们就能保证同一条重链一定都是连在一起的,这样子就可以最小化线段树的修改次数不用 O ( N ) O(N) O(N)的modify了,时间复杂度是 O ( n ∗ l o g n ∗ l o g n ) O(n*logn*logn) O(nlognlogn)

树链剖分的函数主要能分成三个部分,第一个是线段树操作函数,第二个是树链剖分链操作函数,第三个是树链剖分树操作函数;

本质上就是寻找一种方法将树的迭代顺序拆成是一条链,然后就能便于我们去维护各种区间内的值;
例题在acwing上面有;

代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100010,M=N*2;
int n,m;
int w[N],h[N],e[M],ne[M],idx;
int id[N],nw[N],cnt;
int dep[N],sz[N],top[N],fa[N],son[N];
struct seg{
   
	int l,r;
	ll add,sum;
}tr[N*4]
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值