树状数组
树状数组和线段树的实现
如何推导?查看本人的知乎这篇文章:前缀和改进之树状数组 - 知乎 (zhihu.com)
树状数组
功能
单点修改,区间求和 O(logN)
可以在,O(logN)的时间内,动态求前缀和 ( 对比前缀和,修改的话需要O(N) )
注意:树状数组下标一定要从1开始
树状数组初始化
1 | for(int i=1 ; i<=n ; i++) add(i,a[i]); |
小小地解释一下原理:
树状数组中奇数下标和原数组相等
c[x] = 原数组中下标从(x-lowbit(x),x]的和左开右闭
三个基本操作:
1 | int a[N],c[N];//a[N]为原数组,c[N]为树状数组 |
线段树
每个结点都是一个结构体
1 | struct Node{ |
线段树存储
注意结点个数要开 4n 其中n是有多少个数
类似于堆的存储方式,存在一维数组,对于一个序号为x的节点
- 父节点为 x/2 (下取整)
x>>1 - 左子节点为 x*2
x<<1 - 右子节点为 x*2+1
x<< 1 | 1
基本操作
单点修改 O(logN)
区间查询 O(logN)
四个函数
pushup 用子节点信息更新当前节点信息
1 | void pushup(int u){ |
build 在一段区间上初始化线段树
1 | void build(int u, int l, int r){ |
modify 修改某个点的值
1 | void modify(int u, int x, int v){ |
query 查询
1 | int query(int u, int l, int r){ |
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
