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;
}

posted @ 2016-06-07 15:01  Krew  阅读(420)  评论(0)    收藏  举报