非递归线段树实现
ZKW 非递归线段树
参考文章:线段树详解(非递归版)_非递归线段树-CSDN博客
建树:
原数组[1,n] 存在线段树的 [2,n+1] (为了方便区间查询,要空出第一个节点和最后一个节点)
区间查询
若查询[L,R] 区间, 选取L-1和 R+1 两个节点, 向上寻找.
- 每次到达父节点 L-1 查看自己的父亲的右节点是否是R+1(或者自己是不是右节点),
- 如果不是则加上右节点的 val .
- R+1 节点则查看自己的父亲的左节点是否是 L-1(或者自己就是左节点),
- 如果不是 加上左节点的 val .
线段树填充
若该线段树可维护 N 个元素
如果该线段树是满二叉树, 那么会有
线段树下标 + N -1 = 存储下标
而之前为了方便区间查询有:
原数组下标 + 1 = 线段树下标
那么如何确定 N 值?
N 是大于等于n +2 的,且由于要构造满二叉树, N 是 2 的幂次方
存在Lazytag 时该怎么进行区间查询?
非递归是从下往上进行查询的
-
如果题目允许, 可以先打上标记,所有标记都打完之后一次下推所有标记, 然后再开始查询
-
如果标记和查询交错, 那么可以采用标记永久化的方法, 也就是不下推标记.
L-1 与 R+1 节点往上查询的时候, 多带上一个变量, 记录此时已经计算了多少个数,当该节点达到了一个存在 tag标记的节点的时候, 加上tag 对各个数的影响,然后一次一路寻找到根节点, 返回答案
区间修改
#define maxn 100009
int a[maxn];
int sum[maxn<<2];// 区间和
int add[maxn<<2]; // 区间加lazytag
int n; // 原数组元素
int N: // N为扩充元素个数
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
建树
void build(int n){
N =1 ;while(N<n+2)N<<=1;
for(int i =1 ;i<=n;i++)sum[N+i] = a[i];// 直接修改叶子节点标记, 注意因为形成满二叉树, 其实有一些节点是空节点, 为0;
for(int i= N -1 ;i>0;i--){// 更新根节点
sum[i] = sum[ls(i)] + sum[rs(i)];
add[i] = 0;
}
}
点修改
void update(int l,int c){
for(int i = N+l;i>0;i>>=1){
sum[i] += c;
}
}
区间修改(无tag, 单点修改版本)
void change(int l ,int r){
l=l+N-1,r=r+N+1;
// l^s^1 == 0 就代表 l 与 s 相邻, 也就是所有区间统计的内容都已经取完了
int ans =0;
while(l^s^1){
if(~l&1) ans += sum[l^1]; //如果l 是左节点
if(r&1) ans += sum[r^1]; //如果r 是右节点
l >>= 1;r >>= 1; // 寻找父亲节点
}
}
注意l ^r ^1 = 0 除了存在相同的父节点还有一种情况,当然这两种情况都是可以直接退出的,可以所有打上的标记都已经统计完了:
区间修改(区间加版本)
void changeblock(int l,int r,int z){
int i,j,s1=0,s2=0,x=0;
for(i=l+N-1,j=r+N+1;i^j^1;i>>=1,j>>=1){
sum[i] += s1 * z; sum[j] += s2 * z;
if(~i&1) add[i^1] += z, sum[i^1]+= s1*z,s1+=x;// x 为包括的节点数
if(j&1) add[j^1] += z , sum[j^1]+=s2*z, s2+=x;
}
for(;i;i>>=1,j>>=1){// 更新上层
sum[s] += s1* z;
sum[t] += s2* z;
}
}
区间查询(tag 版本, 区间加版本)
void query(int l,int r){
int ans =0,i,j,s1,s2,x=1;
for(i= l+ N-1,j = l+ N +1;i^j^1;i>>=1,j>>=1,x<<=1){
if(add[i]) ans += s1*add[i];
if(add[j]) ans += s2*add[j];
if(~i&1) ans += sum[i^1],s1+=x;
if(j&1) ans += sum[j^1],s2+=x;
}
for(;i;i>>=1,j){
if(add[i])ans+= s1 *add[i];
if(add[j])ans++ s2 *add[j]
}
return ans ;
}
任何时候都有比放弃更好的选择。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)