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 <统计的 ...
随机推荐
- linq中如何在join中指定多个条件
public ActionResult Edit(int id) { using (DataContext db = new DataContext(ConfigurationManager.Conn ...
- UnityEditorWindow自建窗口扩展
这里主要记录UnityEditorWindow的创建,以及常用的API接口样式 1,创建UnityEditorWindow 在Unity目录中,创建一个名为Editor的文件夹(任何位置),然后创建如 ...
- 微信内无法自动跳转外部浏览器打开H5分享链接的解决办法
很多情况下我们用微信分享转发H5链接的时候,都无法在微信内打开,即使开始能打开,过一段时间就会被拦截,拦截后再打开微信会提示 “已停止访问该网址” ,那么导致这个情况的因素有哪些呢,主要有以下四点 1 ...
- 【问题解决方案】Github中的jupyter notebook文件(.ipynb)加载失败/失败
两个方法: 法一:本机安装jupyter notebook的情况下直接下载文件并打开 本机打开的话会在浏览器中显示,地址为localhost:8888,也就是本机 法二:在线打开:利用 'https: ...
- 【学习总结】GirlsInAI ML-diary day-19-面向对象编程
[学习总结]GirlsInAI ML-diary 总 原博github链接-day19 认识面向对象 Python使用类(class)和对象(object),进行面向对象(object-oriente ...
- git常用命令值stash
git stash(git储藏)可用于以下情形: 发现有一个类是多余的,想删掉它又担心以后需要查看它的代码,想保存它但又不想增加一个脏的提交.这时就可以考虑git stash. 使用git的时候,我们 ...
- P5057 [CQOI2006]简单题
题目描述 有一个 n 个元素的数组,每个元素初始均为 0.有 m 条指令,要么让其中一段连续序列数字反转——0 变 1,1 变 0(操作 1),要么询问某个元素的值(操作 2). 例如当 n = 20 ...
- Adding appsettings.json to a .NET Core console app
This is something that strangely doesn’t seem to be that well documented and took me a while to figu ...
- MVC EF 移除建表时自动加上s的复数形式
移除建表时自动加上s的复数形式 public class DBContext : DbContext { public DBContext() : base("name=DBContext& ...
- Forethought Future Cup - Elimination Round
A:签到. #include<bits/stdc++.h> using namespace std; #define ll long long char getc(){char c=get ...