题目请点我
题解:
这是我写的第一道线段树,看大家好多都是把它当作第一道练手。其实线段树作为一种数据结构,比赛时是作为维护工具使用的,风格较为固定,关键要掌握原理,看清楚每一步的含义。所以可以先照着打一遍,然后最好还是能自己不看原来代码重新敲一边,就是这样,理解了的才能真的是自己的。
代码实现:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define MAX 50010
#define LL long long
using namespace std;
int T;
int N;
char s[10];
int num[MAX];
int segTree[MAX<<2|1];
void build(int root,int l,int r);
void update(int pos,int add,int l,int r,int root);
LL query(int a,int b,int l,int r,int root);
int main(){
scanf("%d",&T);
for( int t = 1; t <= T; t++ ){
printf("Case %d:\n",t);
scanf("%d",&N);
for( int i = 1; i <= N; i++ ){
scanf("%d",&num[i]);
}
build(1,1,N);
getchar();
while( cin>>s ){
if( s[0] == 'E' ){
break;
}
int x,y;
scanf("%d%d",&x,&y);
if( s[0] == 'Q' ){
LL res = query(x,y,1,N,1);
printf("%I64d\n",res);
}
else if( s[0] == 'A' ){
update(x,y,1,N,1);
}
else if( s[0] == 'S' ){
update(x,-y,1,N,1);
}
}
}
return 0;
}
void build(int root,int l,int r){
//root是实际存储角标,l=r=临时存储角标
if( l == r ){
segTree[root] = num[l];
return ;
}
int mid = (l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
//求线段和
segTree[root] = segTree[root<<1]+segTree[root<<1|1];
return ;
}
//点更新
void update(int pos,int add,int l,int r,int root){
//定位到更新点
if( l == r ){
segTree[root] += add;
return ;
}
//由pos相对位置决定更新位置
int mid = (l+r)>>1;
if( pos <= mid ){
update(pos,add,l,mid,root<<1);
}
else{
update(pos,add,mid+1,r,root<<1|1);
}
segTree[root] = segTree[root<<1]+segTree[root<<1|1];
return ;
}
//区间和
LL query(int a,int b,int l,int r,int root){
//避免超出范围
if( a > r || b < l ){
return 0;
}
//所求区间完全包含当前区间
if( a<=l && b>=r ){
return segTree[root];
}
int mid = (l+r)>>1;
return query(a,b,l,mid,root<<1)+query(a,b,mid+1,r,root<<1|1);
}