博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树上差分
阅读量:6097 次
发布时间:2019-06-20

本文共 1108 字,大约阅读时间需要 3 分钟。

树上差分建立在差分数组的基础上,所以还不会差分数组的大佬可以先预习一下这篇博客,期望阅读时间5分钟:


引入这样一个例题,给定一棵n(n≤105)个点的树,m(m≤105)次操作,将这棵树上的两点之间的最短路径上的每一个点都加k或者都减k,在这m次操作之后求出每个点的值。

首先,在你没有学过树上差分的时候,你会想到用倍增或者是塔尖求出这两个点的LCA然后暴力更改,显然这样每一次操作时间复杂度最劣会是O(n),显然不能接受。

那么我们现在引入树上差分。

树上差分我们可以先感性的理解为树上的差分数组。

树上差分分为两种,一种是边的差分,另一种是点的差分。

那么今天我们就先来讲一下点的差分。

大家现在一定会想像差分数组从前往后扫一样从根往下扫,每个点存它与它的父亲的差,但是认真想一下,这样会存在一个问题,如果我将一条路径上每个点的值都增加k,那么这条路径上的其它枝杈都要打标记减去k。

如图:

这样当路径上的枝杈过多时,时间复杂度会非常不优。

那么应该怎么办呢?我们思考一下刚开始学OI的时候学到的递归思想来解决这个问题。

那么现在我们定义一个节点u的差分数组B[u]表示它与它所有儿子的加和的差,那么问题就变得简单多,我们只需要在最后统计答案的时候递归处理即可。

那么相比很多人有些疑惑,我们应该怎么做修改呢?

还是那个问题,现在我们要将两个点的最短路径上的点都加k或者减k,暂且设这两个点为uv

那么我们还需要再定义两个点,uvLCAlca(倍增或塔尖求出),lca的直接父亲为father

那么我们在更改的时候只需要做如下操作:

  B[u]+=k;

  B[v]+=k;

  B[lca]-=k;

  B[father]-=k;

那么为什么这么做是正确的呢?

我们可以认为我们在给u节点的差分数组+k的时候也就相当与将u到根的所有节点都加了k,给v节点的修改同理。

那么我们需要将多更改的部分减去,多更改的部分也就是lca多更改了一次,从father到跟节点多更改了两次,所以我们在将B[lca]-=k,B[father]-=k同时就相当于是做了这个操作(B[lca]-=k相当与减掉了lca多更改的那一次和father到跟节点多更改的一次,B[father]-=k相当于是剪掉了father到跟节点多更改的剩下的那一次,叠加即为减去了多更改的部分)。

当所有的操作都完成后只需要DFS递归统计答案即可。


 

如果你觉得你已经学会了树上差分,那么可以跳转这道例题(博客还没有写出来额)


rp++

转载于:https://www.cnblogs.com/wzc521/p/11032383.html

你可能感兴趣的文章
js document.activeElement 获得焦点的元素
查看>>
abb画学号
查看>>
C++ 迭代器运算
查看>>
【支持iOS11】UITableView左滑删除自定义 - 实现多选项并使用自定义图片
查看>>
day6-if,while,for的快速掌握
查看>>
JavaWeb学习笔记(十四)--JSP语法
查看>>
【算法笔记】多线程斐波那契数列
查看>>
java8函数式编程实例
查看>>
jqgrid滚动条宽度/列显示不全问题
查看>>
在mac OS10.10下安装 cocoapods遇到的一些问题
查看>>
angularjs表达式中的HTML内容,如何不转义,直接表现为html元素
查看>>
css技巧
查看>>
Tyvj 1728 普通平衡树
查看>>
[Usaco2015 dec]Max Flow
查看>>
javascript性能优化
查看>>
多路归并排序之败者树
查看>>
java连接MySql数据库
查看>>
转:Vue keep-alive实践总结
查看>>
android studio修改新项目package名称
查看>>
深入python的set和dict
查看>>