题目来源:
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[n].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[n].l=l; anode[n].r=r; anode[n].num=data[l]; return ; } anode[n].l=l; anode[n].r=r; build(l, mid, left(n)); build(mid+1, r, right(n)); pushup(n);// 先递归,后从下往上更新区间和值 } // 线段树更新,从根节点开始, 调用为 update(aim_id, new_num, 1) void update(int aim_id, int new_num, int n){ if(anode[n].l == aim_id && anode[n].r== aim_id ){ anode[n].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[n].l ==l && anode[n].r ==r) return anode[n].num; int mid; mid= (anode[n].l + anode[n].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 ; }