普及向 ZKW线段树!
旧文迁移:本文最初发布于 博客园 qscqesze,原分类:A 人生经验。
啊,是否疲倦了现在的线段树
太弱,还递归!
那我们就欢乐的学习另外一种神奇的线段树吧!(雾
他叫做zkw线段树
这个数据结构灰常好写(虽然线段树本身也特别好写……)
速度快(貌似只在单点更新方面比线段树快……)
是一种自底向上非递归版本的线段树!
首先我们来看一个ppt,《统计的力量》这个是发明人的PPT(啊,ppt内的代码是错的……
好吧,我们来写吧~
首先预备条件:
int M,T[maxn*2+2];
M指的是什么呢?M就指的是这颗zkw线段树最下面的那个点之前的编号是什么
T数组就是这个zkw线段树的数组,由于zkw线段树是一颗满二叉树,所以直接开两倍就好啦~
接下来我们就来建树吧!
以单点更新,区间查询和作为一个例子~
void build(int x)
{
for(M=1;M<=n+1;M<<1);
for(int i=1;i<=n;i++)
scanf("%d",&T[i+M]);
for(int i=M-1;i;i--)
T[i]=T[i<<1]+T[i<<1|1];
}
很显然这是一颗非常弱的从底往上更新的树!
然后updata怎么写呢?qsc仔细想了想,很简单
void updata(int n,int val)
{
T[n+=M]=val;//这个地方是单点修改的哟
for(n>>=1;n;n>>=1)
T[n]=T[n<<1]+T[n<<1|1];
}
哇,其实和线段树是一个意思,直接顺着节点直接往上爬就是了!
query肿么写呢?还是很简单呀
int query(int l,int r)
{
int ans=0;
l=l+M-1,r=r+M+1;
for(;l^r^1;l>>1,r>>=1)
{
if(~l&1)ans+=T[l^1];
if(r&1) ans+=T[r^1];
}
return ans;
}
这个乱七八糟的位运算什么意思呀?
l^r^1的意思,就是左边的这个点和右边这个点是否互为兄弟,或者干脆就是一个点
~l&1 就是判断这个左边这个是否为左儿子,r&1判断这个节点是否为右二子
如果是的话,那就得加上他的兄弟咯~
啊,zkw单点更新区间查询就示范到这儿了,是不是灰常简单呀~
我们首先来搞一道例题:
HDU 1166 敌兵布阵 单点更新,区间查询
//qscqesze
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
#include <stack>
typedef long long ll;
using namespace std;
//freopen("D.in","r",stdin);
//freopen("D.out","w",stdout);
#define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
#define maxn 200001
#define mod 10007
#define eps 1e-9
//const int inf=0x7fffffff; //无限大
const int inf=0x3f3f3f3f;
/*
int buf[10];
inline void write(int i) {
int p = 0;if(i == 0) p++;
else while(i) {buf[p++] = i % 10;i /= 10;}
for(int j = p-1; j >=0; j--) putchar('0' + buf[j]);
printf("\n");
}
*/
//**************************************************************************************
inline ll read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll T[maxn*4];
int M,n;
void build()
{
for(M=1;M<=n+1;M<<=1);
for(int i=1;i<=n;i++)
T[i+M]=read();
for(int i=M-1;i;i--)
T[i]=T[i<<1]+T[i<<1|1];
}
void updata(int x,int val)
{
T[x+=M]+=val;
for(x>>=1;x>=1;x>>=1)
{
T[x]=T[x<<1]+T[x<<1|1];
}
}
ll query(int l,int r)
{
l=l+M-1,r=r+M+1;
ll ans=0;
for(;l^r^1;l>>=1,r>>=1)
{
if(~l&1)ans+=T[l^1];
if(r&1) ans+=T[r^1];
}
return ans;
}
int main()
{
int cas=0;
int t=read();
string s;
for(int cas=1;cas<=t;cas++)
{
memset(T,0,sizeof(T));
printf("Case %d:\n",cas);
n=read();
build();
while(cin>>s)
{
if(s[0]=='E')
break;
int a,b;
a=read(),b=read();
if(s[0]=='A')
updata(a,b);
else if(s[0]=='S')
updata(a,-b);
else
printf("%lld\n",query(a,b));
}
}
}
评论