您的位置:首页 > 其它

hdu 1166 线段树 单点修改 + 询问区间求和 (线段树模板)

2014-06-26 15:07 246 查看
题目来源:
http://acm.hdu.edu.cn/showproblem.php?pid=1166
借鉴大牛李的线段树模板

const int Max_N=50100;
int sum[Max_N<<2] ; // 线段树中每个点需要维护的区间和
int x[Max_N]; // 输入数组
//从下向上更新值
void push_up(int root){
sum[root] = sum[root<<1] + sum[root<<1|1]
}
// 建树,从根节点出发,根节点从1开始
void make_tree(int L, int R, int root){
if(L == R){
sum[root] = x[L];
return ;
}
int mid=(L + R)>>1;
make_tree(L, mid, root<<1 );
make_tree(mid+1, R, root<<1|1);
push_up(root); // 先递归,后从下往上更新区间和值
}
// 将id值增加c, 调入的是整棵树的区间和根节点1
void update(int id, int c, int L, int R, int root)
{
if(L == R){
sum[root]+=c;
return ;
}
int mid=(L + R)>>1;
if(id<=mid )
update(id, c, L, mid , root<<1);
else
update(id,c, mid+1, R, root<<1|1);
push_up(root); // 更新是从上到下寻找需要更改的节点,然后从下往上地更新这些节点的区间和值
}
// 查询区间[l,r] 的 区间和值,在递归时不更改[l,r]区间的写法
更一般(适应性越强)的写法

int query(int l, int r, int L, int R, int root){
  if(l<=L && R <= r)
    return sum[root];
  int mid=(L + R)>>1;
  if(mid >= r)
    return query(l,r,L, mid, root<<1);
  else if(mid < l)
    return query(l,r,mid+1, R, root<<1|1);
  else
    return query(l,r,mid+1, R, root<<1|1)  +  query(l , r, L, mid, root<<1);
}

// 查询如果仅是加法, 就可以套这个模板
int query(int l, int r, int L, int R, int root)
{
if(l <= L && R <= r)
return sum[root];
int mid=(L + R)>>1;
int ans=0;
if(l<= mid)
ans+=query(l, r, L, mid, root<<1);
if(r>mid)
ans += query(l, r, mid+1, R, root<<1|1);
return ans;
}


 

 

 

 

代码如下:

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <stack>
#include <string>
#include <string.h>
#include<cstring>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <set>
#include <math.h>
#include <cmath>
#include <map>
#include <queue>
using namespace std ;
typedef long long LL ;

// 线段树 单点修改,区间求和
#define left(x) (x<<1)
#define right(x) ((x<<1) + 1)
const int maxn=50005;
// 此线段树需要维护的附加信息是num,指的是每个节点所代表区间【l,r】之和
struct tree{
int l,r,num;
};

tree anode[maxn<<2]; // 线段树的节点估计为2*maxn 个
int  data[maxn];
// 附加信息的向上更新只与该节点或者节点的子节点有关,故可以扩展线段树
void pushup(int n){
anode
.num=anode[left(n)].num + anode[right(n)].num;
return ;
}// 向上更新
// 建线段树,从根节点1开始,调用为 build(1,n,1)
void build(int l, int r, int n){
int mid;
mid=(l+r)>>1;
if(l==r){
anode
.l=l;
anode
.r=r;
anode
.num=data[l];
return ;
}
anode
.l=l;
anode
.r=r;
build(l, mid, left(n));
build(mid+1, r, right(n));
pushup(n);// 先递归,后从下往上更新区间和值
}
// 线段树更新,从根节点开始, 调用为 update(aim_id, new_num, 1)

c658
void update(int aim_id, int new_num, int n){
if(anode
.l == aim_id && anode
.r== aim_id ){
anode
.num += new_num;
return ;
}
if(anode[ left(n) ].l <= aim_id && anode[left(n)].r >=aim_id)
update(aim_id, new_num, left(n));
else update(aim_id, new_num, right(n));
pushup(n);// 先递归需要更改的节点,然后从下往上的更新区间和值
return ;
}
// 线段树查询,从根节点开始, 调用为 query(l,r, 1)
int query(int l, int r, int n){
if(anode
.l ==l && anode
.r ==r)
return anode
.num;
int mid;
mid= (anode
.l + anode
.r)>>1;
if(mid >=r) return query(l,r,left(n));
else if(mid< l) return query(l,r,right(n));
else return query(l,mid,left(n)) + query(mid+1, r, right(n));
}

int  main(){
int ca,k=1;
scanf("%d",&ca);
while(ca--){
int n;
scanf("%d",&n);
for(int i=1 ; i<=n; i++)
scanf("%d",&data[i]);
build(1,n,1);
printf("Case %d:\n",k++);
char od[12];
while(1){
scanf("%s",od);
if(od[0] == 'E') break;
int a,b;
scanf("%d%d",&a,&b);
if(od[0] == 'A')
update(a,b,1);
else if(od[0] == 'S')
update(a,-b,1);
else
printf("%d\n",query(a,b,1));
}
}
return 0 ;
}


 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: