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线段树学习笔记的更多相关文章

  1. 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解

    什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...

  2. JSOI2008 Blue Mary开公司 | 李超线段树学习笔记

    题目链接:戳我 这相当于是一个李超线段树的模板qwqwq,题解就不多说了. 代码如下: #include<iostream> #include<cstdio> #include ...

  3. 仙人掌&圆方树学习笔记

    仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...

  4. 普及向 ZKW线段树!

    啊,是否疲倦了现在的线段树 太弱,还递归! 那我们就欢乐的学习另外一种神奇的线段树吧!(雾 他叫做zkw线段树   这个数据结构灰常好写(虽然线段树本身也特别好写……) 速度快(貌似只在单点更新方面比 ...

  5. 线段树和zkw线段树

    作者作为一个蒟蒻,也是最近才自学了线段树,不对的地方欢迎大佬们评论,但是不要喷谢谢 好啦,我们就开始说说线段树吧 线段树是个支持区间操作和查询的东东,平时的话还是蛮实用的 下面以最基本的区间加以及查询 ...

  6. ZKW线段树 非递归版本的线段树

    学习和参考 下面是支持区间修改和区间查询的zkw线段树模板,先记下来. #include <algorithm> #include <iterator> #include &l ...

  7. 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 ...

  8. ZKW线段树

    简介 zkw线段树虽然是线段树的另一种写法,但是本质上已经和普通的递归版线段树不一样了,是一种介于树状数组和线段树中间的存在,一些功能上的实现比树状数组多,而且比线段树好写且常数小. 普通线段树采用从 ...

  9. zkw线段树详解

    转载自:http://blog.csdn.net/qq_18455665/article/details/50989113 前言 首先说说出处: 清华大学 张昆玮(zkw) - ppt <统计的 ...

随机推荐

  1. Photoshop入门教程图解版

  2. linux安装redis操作

    redis官网地址:http://www.redis.io/ 最新版本:2.8.3 在Linux下安装Redis非常简单,具体步骤如下(官网有说明): 1.下载源码,解压缩后编译源码. $ wget ...

  3. mongodb解决只能本地连接不能远程连接问题

    本机windows7 ,装了vagrant盒子,并在盒子上装了mongodb服务,本机连接虚拟机时连不上. 解决方法: 修改虚拟机上 mongodb.conf 文件,将bind_ip = 127.0. ...

  4. 小程序组件中有bindinput监听报异常

    真机上有问题,ide上是没问题的,   组件有处理函数,结果异常说页面没有处理函数,加上处理函数后就不报异常了.

  5. 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么

    看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...

  6. vue.js 列表追加项写法

    <ul id="app"> <template v-for="site in sites"> <li>{{ site.nam ...

  7. RedisCache 缓存

    /// <summary> /// 这是包装过公用的,用于本站而已. /// </summary> /// <author>rixiao</author> ...

  8. 001 java简介

    JavaSE(Java Standard Edition):标准版本,定位在个人计算机上的应用.(失败) JavaEE(Java Enterprise Edition):企业版,定位在服务器端的应用. ...

  9. 机器学习---感知机(Machine Learning Perceptron)

    感知机(perceptron)是一种线性分类模型,通常用于二分类问题.感知机由Rosenblatt在1957年提出,是神经网络和支持向量机的基础.通过修改损失函数,它可以发展成支持向量机:通过多层堆叠 ...

  10. [USACO19FEB]Mowing Mischief

    题目大意: 给定平面上的一些点,求这些点的一个\(LIS\),并且还需要满足下列式子最小: \[ \sum_{i=1}^{n-1}(a[i+1].x-a[i].x)*(a[i+1].y-a[i].y) ...