题目来源:
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
#include
#include
#include
#include
#include <string>
#include <string.h>
#include
#include
#include
#include
#include <set>
#include
#include
#include