zkw线段树
zkw线段树
传统线段树是基于递归的分治算法,常数太大,书写复杂度高。因此,清华大学的zkw提出了一种新的基于二进制运算的非递归线段树——zkw线段树。
操作:
(1)区间查询: 我们让叶节点全部固定在最后一层,由于查询是连续的,每一层至多访问两个节点,以最左边的节点为例,如果它是父亲的右儿子,则答案加上它,再右移一位,右端同理。最后将两段结点向上置为它们的父亲,直到区间长度为0
(2)单点修改:直接找到叶节点修改,再从下往上维护即可。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
using namespace std;
const int maxn=8000000+10;
int M,n,m,k,x,y,a[maxn],t[maxn];
void init() //初始化
{
for (M=1;M<n;M*=2) {}
M--;
rep(i,1,n) t[i+M]=a[i];
dep(i,M,1) t[i]=t[i<<1]+t[(i<<1)+1]; //建树
}
void add(int x,int k) //单点修改
{
x+=M;t[x]+=k;x>>=1;
while (x) {t[x]=t[x<<1]+t[(x<<1)+1];x>>=1;} //递推更新
}
int query(int x,int y) //区间查询
{
int ans=0;x+=M;y+=M;
while (x<=y)
{
if (x==y) {ans+=t[x];break;}
if (x&1) ans+=t[x++];
if (!(y&1)) ans+=t[y--];
x>>=1;y>>=1;
}
return ans;
}
int main()
{
scanf("%d",&n);
rep(i,1,n) scanf("%d",&a[i]);
init();
scanf("%d",&m);
rep(i,1,m)
{
scanf("%d%d%d",&k,&x,&y);
if (k==1) add(x,y); else printf("%d\n",query(x,y));
}
return 0;
}

浙公网安备 33010602011771号