树状数组和线段树的总结
程序员文章站
2023-04-08 09:56:20
先说树状数组吧 主要有lowbit,update,getsum lowbit的作用就是找到该节点的父节点或子节点 图 (https://www.cnblogs.com/George1994/p/7710886.html) 注意了 a数组存的是原来的数 c数组的意义代表着c[i] 就是前i项的和 线段 ......
先说树状数组吧 主要有lowbit,update,getsum
int lowbit(int x) { return x&(-x); }
int update(int x,int date) { while(x<=y) { c[x]+=date; x+=lowbit(x); } }
int getsum(int x) { int ans=0; while(x>0) { ans+=c[x]; x-=lowbit(x); } return ans; }
lowbit的作用就是找到该节点的父节点或子节点 图 (https://www.cnblogs.com/George1994/p/7710886.html)
注意了 a数组存的是原来的数 c数组的意义代表着c[i] 就是前i项的和
线段树的话
差不多两个数组搞定一个tree【n】和一个add【n】
先是建立树
线段树是从1这个节点开始的
void build(int l,int r,int k)//l,r为建树的范围 { if(l==r) { cin>>tree[k]; return ; } int m=(l+r)>>1; build(l,m,k<<1);//递归建立数 build(m+1,r,k<<1|1); tree[k]=tree[k<<1]+tree[k<<1|1];//求和 }
自我觉得这个是比较灵活的,对这个改动一下就成为不同的功能,比如最大值
void build(int l,int r,int k) { if(l==r) { cin>>tree[k]; return ; } int m=(l+r)>>1; build(l,m,k<<1); build(m+1,r,k<<1|1); //tree[k]=tree[k<<1]+tree[k<<1|1]; tree[k]=max(tree[k<<1],tree[k<<1|1]); }
这样就变成了父节点 为子节点的最大值
然后是点更新
void update(int ee,int c,int l,int r,int k) { if(l==r) { tree[k]+=c; //tree[k]=c; 这样就是更改这个数,而不是加 return ; } int m=(l+r)>>1; if(ee<=m) update(ee,c,l,m,k<<1);//ee为需要更新的叶子节点,通过递归找 else update(ee,c,m+1,r,k<<1|1); tree[k]=tree[k<<1]+tree[k<<1|1]; }
然后是区间更新 ,这里需要懒标记,这个确实比较难理解
void update(int x,int y,int c,int l,int r,int k)//x,y为需要更新区间,l,r为k这一节点的管理范围 { if(x<=l&&y>=r) { tree[k]=c*(r-l+1);//这一点为c乘以这一点管理的数量 add[k]=c;//把这一点标记一下,为懒标记 return;//注意是结束了 } int m=(l+r)>>1; pushdown(k,m-l+1,r-m);//下推标记 if(x<=m) update(x,y,c,l,m,k<<1); if(y>m) update(x,y,c,m+1,r,k<<1|1);//注意 这里不是else 而是都要更新并查找 tree[k]=tree[k<<1]+tree[k<<1|1]; }
void pushdown(int k,int ln,int rn)//ln,rn为左子树,右子树的数字数量。 { if(add[k]) { add[k<<1]+=add[k]; add[k<<1|1]+=add[k];//传递这个标记 sum[k<<1]+=add[k]*ln; sum[k<<1|1]+=add[k]*rn; add[k]=0; } }
上面是要求和的下推标记,但如果说是这道题
为这个区间都改变成一样的数,而不是相加一样的数
void pushdown(int k,int ln,int rn){ if(add[k]){ add[k<<1]=add[k]; add[k<<1|1]=add[k];
sum[k<<1]=add[k]*ln; sum[k<<1|1]=add[k]*rn; add[k]=0; } }
最后是区间求和
int query(int x,int y,int l,int r,int k) { if(x<=l&&r<=y) { return tree[k]; } int m=(l+r)>>1; pushdown(k,m+1-l,r-m); int ans=0; if(x<=m) ans+=query(x,y,l,m,k<<1); if(y>m) ans+=query(x,y,m+1,r,k<<1|1); return ans; }
上一篇: php+layui实现图片上传与预览
推荐阅读
-
树状数组和线段树的总结
-
php数组和链表的区别总结
-
P3924 康娜的线段树(マジやばくね)(线段树、期望、前缀和)难度⭐⭐⭐★
-
hdu 1754 I Hate It (树状数组求区间最大和)(线段树单点修改)
-
见微知著----POJ2352(树状数组 或 线段树)
-
ICPC网络赛 Ryuji doesn't want to study (线段树/树状数组)
-
Leetcode-307. 区域和检索 - 数组可修改 Range Sum Query - Mutable (线段树Segment Tree)-超详细Python
-
树状数组的简单介绍和C++实现
-
洛谷P3372 【模板】线段树 1(树状数组)
-
洛谷P3924 康娜的线段树(期望 前缀和)