题目链接 HDOJ 1166
这是一个基本没有包装的线段树。问的很直白,就是要求高效的更新一棵树的节点值,高效的求任意连续区间内的元素的和。而这正是线段树的基本要求
所以是很好的一道线段树入门题,帮助理解线段树的建立,更新,查询的作用。
线段树是一种数据结构,基本的操作有build,query,update等等,用于对树中的元素进行操作。
以上三个操作基本都有了固定的格式,也可以说是模板
代码如下:
#include <cstring>
#include <iostream>
#include <cstdio>
#define maxn 50005
int sum[maxn<<2];//位运算,左移两位实际上相当于十进制中乘2的平方
void pushup(int node)//overwrite the value of current node by its lson+rson即更新节点node的值,用两个子节点的值的和来替代
{
sum[node]=sum[node*2]+sum[node*2+1];
}
void build(int l,int r,int node)//即所谓的“建树”,从一号节点即根节点(root)开始,用递归的思路将区间细分直至到每个单点,存入值。
{
if(l==r)
{
scanf("%d",&sum[node]);
return;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pushup(node);
}
void update(int p,int add,int l,int r,int node)//point update 即 单点更新,线段树更新操作的相对简单的一个。形参中的p即将要更新的元素位置。也是用递归的方法
{ //找到p所在的区间,更新那个值,注意这里的p是相对于数列角标而言的,并不是节点的代号。。
if(l==r)
{
sum[node]+=add;//这时候的node实际上已经成为p了
return;
}
int m=(l+r)/2;
if(p<=m)
{
update(p,add,l,m,node*2);
}
else
{
update(p,add,m+1,r,node*2+1);
}
pushup(node);
}
//对于update操作,我们是想以p为指标找到合适的区间对应的node更新之
int query(int lq,int rq,int l,int r,int node)//其实大致思路同之前都是一样的了,只不过之前找单点,现在找一堆在指定范围内的单点,取其值并加在一起
{
if(lq<=l&&rq>=r)
return sum[node];
int m=(l+r)/2;
int tmp=0;
if(lq<=m) tmp+=query(lq,rq,l,m,node*2);
if(rq>m) tmp+=query(lq,rq,m+1,r,node*2+1);
return tmp;
}
int main()
{
int t,numop,num;
int coun=0;
char op[20];
scanf("%d",&t);
while(t--)
{
coun++;
scanf("%d",&num);
build(1,num,1);
printf("Case %d:\n",coun);
while(scanf("%s",op)!=EOF)
{
if(op[0]=='E')break;
int a,b;
scanf("%d%d",&a,&b);
if(op[0]=='Q')//简单的识别“命令”
{
printf("%d\n",query(a,b,1,num,1));
}
else if(op[0]=='A')
update(a,b,1,num,1);
else
update(a,-b,1,num,1);
}
}
}