zkw线段树
1.来源 zkw统计的力量
醍醐灌顶啊
zkw线段树是一颗满二叉树
001
010 011
100 101 110 111
也许有助于理解一些位运算
一.建树
for(M=1;M<=n;M<<=1);
for(int i=1;i<=n;i++){
a[i]=number();tr[M+i]=a[i];
}
M为叶子个数,前n层共M-1个点
M保证最后一层要有>n个点
注意,叶子节点的第一个不放东西(也就是tr[M])
二.维护
for(int i=M-1;i;i--)tr[i]=tr[i<<1]+tr[i<<1|1];
三.单点查询
return tree[M+i]
四.区间查询
这很有意思
比如说查询[s,t]
转换为开区间(s,t)
那么显然s的右节点,t的左节点是有用的
于是
for(int s=l[i]+M-1,t=r[i]+M+1;s^t^1;s>>=1,t>>=1){
if(~s&1)ans=max(aa,tr[s^1]);
if(t&1)ans=max(aa,tr[t^1]);
}
补充:~为按位取反
也就是如果s为左子树 就将他的右子树加进答案
也就是如果t为右子树 就将他的左子树加进答案
s^t^1意思是s,t为同一棵子树的左右节点
五.单点更新
void change(int k,int v){
tree[k+M]=v;
for(int i=k+M;i;i>>=1)tree[i]=tree[i<<1]+tree[i<<1|1];
}
六.区间更新
差分思想