zkw线段树学习笔记
zkw线段树学习笔记
今天模拟赛线段树被卡常了,由于我自带常数 \(buff\),所以学了下zkw线段树。
平常的线段树无论是修改还是查询,都是从根开始递归找到区间的,而zkw线段树直接从叶子结点开始操作。
建树
首先,我们需要把线段树补成一个堆形态的树,原序列在最后一层(最后一层的左右要留空,后面再讲为什么),这样一来,就可以轻松得出:原序列里第 \(x\) 个元素在线段树里的编号就是 \(x+2^k\) (其中 \(k\) 为线段树的深度,根节点深度为 \(0\) )
大概就是这样 :

不难发现最后一层节点掐头去尾,就是原序列编号加上二进制最高位上的 \(1\)。
代码实现也非常简单:
segment_tree(const int n = 0) {
for (M = 1; M - 2 < n; M <<= 1); //M是最后一层的节点个数
for (int i = 1; i <= n; ++i)
t[i + M] = in();
for (int i = M - 1; i; --i)
t[i] = t[i << 1] + t[i << 1 | 1]; //合并子树信息
}
单点查询
直接查
单点修改
。。直接上代码:
void update(int p) {
for (p += M; p; p >>= 1) t[p] += k;
}
区间操作
若当前操作区间为 \([x,y]\),可以把它先转为开区间 \((x-1,y+1)\) (最后一层左右要留空的原因),设此开区间左右端点在线段树的编号为 \(l,r\)。
\(l, r\) 同时向它们的父亲节点跳,若 \(l\) 是它父亲的左儿子,则它父亲的右儿子被操作( \(r\) 与 \(l\) 对称),直到 \(l,r\) 的父亲相同。
可以配合图片理解:

上图中:蓝色为 \(l,r\) 会跳到的点。因为查询区间为 \(l\) 右边和 \(r\) 左边组成的区间,当 \(l\) 为父亲的左儿子时,它父亲的右儿子一定在它左边( \(r\) 与 \(l\) 对称)。
区间修改、查询
这里以区间加法为例;
在普通的线段树中,一般用 \(lazy\) \(tag\) 来解决这个问题,zkw线段树同样可以,但从上向下操作、下放 \(lazy\) \(tag\) 等操作并不优雅 常数大。
可以采用标记永久化,随用随查,按zkw的说法——永久化的标记就是值。
考虑上文提到的区间操作的过程,自下向上走的过程中,根据遇到的标记来计算贡献。
具体实现细节可以看代码:
void modify(int l, int r, ll k) {
int lnum = 0, rnum = 0, now = 1;
//lnum 表示当前左端点走到的子树有多少个元素在修改区间内 (rnum与lnum对称)
//now 表示当前端点走到的这一层有多少个叶子节点
for (l = l + M - 1, r = r + M + 1; l ^ r ^ 1; l >>= 1, r >>= 1; now <<= 1) {
t[l] += k * lnum, t[r] += k * rnum;
if (~l & 1) t[l ^ 1] += k * now, add[l ^ 1] += k, lnum += now;
if (r & 1) t[r ^ 1] += k * now, add[r ^ 1] += k, rnum += now;
}
for (; l; l >>= 1, r >>= 1)
t[l] += k * lnum, t[r] += k * rnum;
}
long long query(int l, int r) {
int lnum = 0, rnum = 0, now = 1;
long long ret = 0;
for (l = l + M - 1, r = r + M + 1; l ^ r ^ 1; l >>= 1, r >>= 1, now <<= 1) {
if (add[l]) ret += add[l] * lnum;
if (add[r]) ret += add[r] * rnum;
if (~l & 1) ret += t[l ^ 1], lnum += now;
if (r & 1) ret += t[r ^ 1], rnum += now;
}
for (; l; l >>= 1, r >>= 1)
ret += add[l] * lnum, ret += add[r] * rnum;
return ret;
}
参考文献:《统计的力量》—— zkw
zkw线段树学习笔记的更多相关文章
- 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解
什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...
- JSOI2008 Blue Mary开公司 | 李超线段树学习笔记
题目链接:戳我 这相当于是一个李超线段树的模板qwqwq,题解就不多说了. 代码如下: #include<iostream> #include<cstdio> #include ...
- 仙人掌&圆方树学习笔记
仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...
- 普及向 ZKW线段树!
啊,是否疲倦了现在的线段树 太弱,还递归! 那我们就欢乐的学习另外一种神奇的线段树吧!(雾 他叫做zkw线段树 这个数据结构灰常好写(虽然线段树本身也特别好写……) 速度快(貌似只在单点更新方面比 ...
- 线段树和zkw线段树
作者作为一个蒟蒻,也是最近才自学了线段树,不对的地方欢迎大佬们评论,但是不要喷谢谢 好啦,我们就开始说说线段树吧 线段树是个支持区间操作和查询的东东,平时的话还是蛮实用的 下面以最基本的区间加以及查询 ...
- ZKW线段树 非递归版本的线段树
学习和参考 下面是支持区间修改和区间查询的zkw线段树模板,先记下来. #include <algorithm> #include <iterator> #include &l ...
- V-Parenthesis 前缀+ZKW线段树或RMQ
Bobo has a balanced parenthesis sequence P=p 1 p 2…p n of length n and q questions. The i-th questio ...
- ZKW线段树
简介 zkw线段树虽然是线段树的另一种写法,但是本质上已经和普通的递归版线段树不一样了,是一种介于树状数组和线段树中间的存在,一些功能上的实现比树状数组多,而且比线段树好写且常数小. 普通线段树采用从 ...
- zkw线段树详解
转载自:http://blog.csdn.net/qq_18455665/article/details/50989113 前言 首先说说出处: 清华大学 张昆玮(zkw) - ppt <统计的 ...
随机推荐
- 分布式存储ceph——(4)ceph 添加/删除osd
一.添加osd: 当前ceph集群中有如下osd,现在准备新添加osd:
- 将WTL应用向导添加到VS2019
WTL 简介 WTL 全称是 Windows Template Library,像 MFC 一样使用 C++ 的面向对象技术对 Win32 接口进行了封装,使之便于开发 Windows 程序.相对于 ...
- Photoshop入门教程图解版
- selenium webdriver 如何实现将浏览器滚动条移动到某个位置
说明: 在做selenium webdriver 在做UI 自动化时,有些页面时使用懒加载的形式显示页面图片,如果在不向下移动滚动条时,获取到的图片会是网站的默认图片和真实的图片不相符. 所以研究了 ...
- ABP实践(1)-通过官方模板创建ASP.NET Core 2.x版本+vue.js单页面模板-启动运行项目
1,打开ABP官网下载模板页面 2,根据下图选择对应的选项及输入项目名 注:上图验证码下方的选择框打钩表示下载最新稳定版,不打钩表示下载最新版本(有可能是预览版) 3,解压下载的压缩包 解压之后是个a ...
- js回调地域 和 用promise解决方法
回调地狱: function3({cb3()}){ function2({cb2(cb3)}){ //cb2触发了cb3,并传值 function1({cb1(cb2)}){ //cb1触发了cb2, ...
- 原型设计的工具-----Axure RP
原型设计的工具-----Axure RP 1.原型设计的工具 目前能用于原型设计的工具有很多,其中有七种比较好. (1) Axure RP (2) Mockplus (3) Jus ...
- windows系统下升级nodejs
别整那些有的没得,直接Win+R 输入:npm config ls 找到nodejs安装路径 然后上nodejs官网,下载最新安装程序,指定旧版本目录,直接安装覆盖掉 啥用n模块啥得,不适合俺们微软体 ...
- Codeforces 1093D Beautiful Graph(二分图染色+计数)
题目链接:Beautiful Graph 题意:给定一张无向无权图,每个顶点可以赋值1,2,3,现要求相邻节点一奇一偶,求符合要求的图的个数. 题解:由于一奇一偶,需二分图判定,染色.判定失败,直接输 ...
- MySQL架构备份之M-S-S级联备份
M--S1--S2 级联复制 master—>slave1—>slave2 master需要开启二进制日志 中间的slave1也需要打开二进制日志,但是它默认不把应用master的操作记录 ...