树状数组和线段树
lowbit函数
lowbit函数指的是将元素与元素的补码按位与,即a&-a,这个值返回的是从右数第一个1开始的值
例如 6&-6, 6二进制位为110,所以6的lowbit函数值为10,即十进制下的二
ll lowbit(ll num)
{
return num&-num;
}
树状数组
首先我们可以把一整个数组分为若干小部分,然后让这几个小部分叠加就可以得到数组总的和。例如,我想求a[91],我可以先求c[88],发现c[88]管理2个数,再找c[86],这样一直进行下去就可以了。
c又是什么呢?例如c[6],它的lowbit函数为2,因此它管理两位数,所以c[6]=a[5]+a[6]
奇数位的c[i]只有他自己,而偶数位c[i]为2的k次方
单点修改
llvm
void add(int x, int k) { |
这个函数是把a[x]加上k,小于x的c不用修改
关键是x=x+lowbit(x)
从此图中我们可以看出,要想求偶数位节点大小,需要将所有子节点加起来,先要加自己和比自己小一位的奇数,再加上所有i+lowbit(i)=8的偶数
求和
llvm
int getsum(int x) { // a[1]……a[x]的和 |
建立
excel
void init() { |
x86asm
int kth(int k) { //权值树状数组查询第k小 |
线段树
含义:线段树指的是将一个区间不断二分所形成的一个二叉树,根结点代表arr[0:N]区间所对应的信息,接着根结点被分为两个子树,分别存储arr[0:(N-1)/2]及arr[(N-1)/2+1:N]两个子区间对应的信息
初始化:注意此处我们对于segmentTree]数组的索引从1开始算起。则对于数组中的任意结点i,其左子结点为2*i
,右子结点为2*i + 1
,其母结点为i/2。
递归实际意义是先向底层递归,然后从底层向上回溯,p的意思是节点的编号
arduino
void build(int s, int t, int p) { |
区间修改
区间修改指的是把区间内连续多个数同时修改
标记的作用是记录每次、每个节点要更新的值
另一种写法
当使用lazy函数时,会让下一层的数加上相应的数并附上相应懒标记,同时根节点的懒标记将被清除,这样一层层往下就可以让每一个数都加上该值
excel
struct node |
区间查询
这里的push_down就是另一种写法中的lazy
总代码
pgsql
|
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment