线段树,看图理解吧.自己理解自己画的.(有错请告诉我,我只是个新手)
操作:单点修改,单点查询.
操作:区间查询:
建树
**链接:**http://acm.hdu.edu.cn/showproblem.php?pid=1166
线段树代码:
#include<bits/stdc++.h> //HDU 1164的AC代码 敌兵布阵
using namespace std; //线段树--------建树get、单点查询get、单点修改get、区间查询、区间修改
#define inf 50000
int grade[inf];
struct ndoe{
int low, high, num; //maxn是数值
}tree[inf<<2]; // >>1 == / 2 <<2 == *4 <<1|1 = *2+1;
int build(int root, int low, int high){ //建树 OK
tree[root].low = low;
tree[root].high = high;
if(low == high) {
//到达叶子结点
return tree[root].num = grade[low];
}
int a, b, mid = (low + high)>>1; //>>1 == /2;
a = build(root<<1,low,mid); //<<1 == *2; 乘2 (建左节点); L,mid
b = build(root<<1|1,mid+1,high); // <<1|1 == *2+1; 乘2加1(建右节点) mid,r
return tree[root].num = a + b; //保存根左右节点的最大值 到达叶子结点的时候, return grade[l]; a+b就是叶子的上一层的num;
}
int que(int root, int low, int high){ //查询区间学生的成绩
if(tree[root].low > high || tree[root].high < low) { //树的左子树 -- 它的右端点的值比 查询区间的左 要小;即这颗左子树 不在查询区间内,return 0;
return 0; //树的右子树 -- 它的左端点的值比 查询区间的右 要大,即这颗右子树 不在查询区间内,return 0;
} //简单来说就是 去掉不在查询范围内的左右子树
if(tree[root].low >= low && tree[root].high <= high) { //然后呢,找子树(该子树的左右孩子都在该区间内),return 该值;;就不用往下找了
return tree[root].num;
}
int a,b,mid = (tree[root].low + tree[root].high)>>1;
a = que(root<<1,low,high); //访问左结点
b = que(root<<1|1,low,high); //访问右节点
return a+b; //回溯传递num
}
//单点查询 与 单点更新 有异曲同工之妙; //二分查找 + 回溯更新
void update(int root,int pos,int num){ // *单点更新,过程是从根开始向下找pos的结点,然后单点更改,最后往上去维护线段树 ;
if(tree[root].low == tree[root].high){
tree[root].num += num; //单点查询的话 直接 return tree[root].num;
return;
}
int mid = (tree[root].low + tree[root].high)>>1;
if(pos <= mid){ //如果查询的位置在.
update(root<<1,pos,num); //左子树,一直递归到叶子节点
}else {
update(root<<1|1,pos,num); //右子树,一直递归到叶子节点
}
tree[root].num = tree[root<<1].num + tree[root<<1|1].num; // <<1 == *2 ;>>1 == /2; //单点查询的话,这一句不要
} //从叶子节点一直回溯上去更新他的父亲节点
int main() {
int n, m;
while(scanf("%d",&m) != EOF && m){
for(int cc = 0;cc < m;cc++){
scanf("%d",&n);
memset(grade,0,sizeof(grade));
for(int i = 1; i <= n; i++) {
scanf("%d",&grade[i]);
}
build(1,1,n); //建树 root L R
getchar();
char ch[15];int title = 1; //command
while(scanf("%s",&ch) != '\0'){
int a, b;
if(title){
printf("Case %d:\n",cc+1);title = 0;
}
if(ch[0] == 'Q'){
scanf("%d%d",&a,&b);
getchar();
printf("%d\n",que(1,a,b)); //查找区间
}else if(ch[0] == 'E'){
break;
}
else if(ch[0] == 'S'){
scanf("%d%d",&a,&b);
getchar();
update(1,a,b*-1); //根 序号 更改的值
}else if(ch[0] == 'A'){
scanf("%d%d",&a,&b);
getchar();
update(1,a,b); //根 序号 更改的值
}
}
}
}
return 0;
}