zkw线段树学习笔记
-
zkw线段树是什么
zkw线段树,顾名思义,是一种线段树。
他是线段树的非递归形式,虽然没递归版线段树那么通用,但它的常数与码量吊打递归版线段树。 -
zkw线段树的构造
说了那么多,不会写也没用啊。
递归式线段树自上往下遍历,即从根节点到叶节点,再回到根节点。
zkw则正好相反,直接从叶节点到根节点。
这就要我们记录下每一个叶节点的位置。
但在一般情况下不太好记录。
![image]()
如图,每个叶节点的位置不太规律。
但有一种特殊情况。
![image]()
也就是叶节点的个数是2的次幂的时候,线段树是一棵满二叉树。
zkw线段树的方法就是在原数列后面补0,使其变为满二叉树的形态。
这样叶子节点就很好找。
构建代码如下:int M,tr[N<<2],n;//n为原始数据个数,tr为线段树,M为填充后数据个数 void build(){ for(M=1;M<=n;M<<=1); //根据需要自行补充 } -
zkw线段树单点操作
可以发现,\(M\)既是填充后数据个数,也是填充后第一个数据的编号,将其留空(有用)
因此,原数据第\(i\)个对应的叶节点编号为\(i+M\)
单点修改就在叶节点直接修改,向上pushup//单点增加代码 void modify(int pos,int x){ pos+=M;tr[pos]+=x;pos>>=1; while(pos){ tr[pos]=tr[pos<<1]+tr[pos<<1|1]; } }单点查询更加简单。相信不用说了。
-
zkw线段树区间操作
区间查询就当然不能一个一个查了这和暴力有什么区别
正解:设两个指针\(s\),\(t\),初始时分别指向\(l-1\),\(r+1\)的位置(0的位置派上用场了)。
然后同步向上跳,父亲节点相同(即成为兄弟时)时停止向上跳。
如果\(s\)为父亲的左儿子,那将\(s\)兄弟的数据合并。
因为\(s\)肯定包含\(l-1\),且\(t\)不为\(s\)兄弟,所以\(s\)兄弟数据在\(l,r\)范围内。
同理,如果\(t\)为父亲的右儿子,那将\(t\)兄弟的数据合并。



浙公网安备 33010602011771号