线段树

一: 区间求和

给定一个数组A,定义Add(s, t, d)的操作为对A[s]...A[t]加d,定义Query(s, t)的操作为查询A[s] + ... + A[t]的值
实现 :每条线段加一个sum属性,用来保存<s,t>的部分和,再加一个d属性,保存A[s]...A[t]的共同增量,Add操作的时候
只需遍历到匹配线段,修改其d属性,不用再往下修改被匹配线段覆盖的孩子节点了。求A[s]+...+A[t]的时候,
把<s,t>的sum和那些覆盖<s,t>的线段的累计增量乘以(t-s+1)加起来即为所求:
A[s]+...+A[t] = <s,t>'s sum + 累计增量*(t-s+1)

 1 传入数组num[]初始值,传出l到r段num[]数组的总和ans;
2 操作1:build(l, r, id) 初始化线段树
3 2:add(l,r,val,id) 将l到r段num[]数组的值都加上val;
4 3:query(int l,int r,int id) 查询l到r段num[]数组的总和ans;
5
6 const int Max = 100050;
7
8 #define L(x) ((x)<<1)
9 #define R(x) ((x)<<1|1)
10
11 struct node{
12 int l,r;
13 int mid(){ return (l+r)>>1; }
14 long long sum,add;
15 }sg[3*Max];
16 int num[Max];
17 long long ans;
18
19 void build(int l, int r, int id){
20 sg[id].l = l; sg[id].r = r;
21 sg[id].add = 0;
22 if(l == r) sg[id].sum = num[l];
23 else{
24 build(l, sg[id].mid(), L(id));
25 build(sg[id].mid()+1, r, R(id));
26 sg[id].sum = sg[L(id)].sum + sg[R(id)].sum;
27 }
28 }
29 void add(int l,int r,int val,int id){
30 if(sg[id].l==l&&sg[id].r==r){
31 sg[id].add+=val;
32 return ;
33 }
34 sg[id].sum+=(r-l+1)*val;
35 if(l<=sg[L(id)].r) add(l,min(r,sg[L(id)].r),val,L(id));
36 if(r>=sg[R(id)].l) add(max(l,sg[R(id)].l),r,val,R(id));
37 }
38 void query(int l,int r,int id){
39 ans+=(r-l+1)*sg[id].add;
40 if(sg[id].l==l&&sg[id].r==r) ans+=sg[id].sum;
41 else {
42 if(l<=sg[L(id)].r) query(l,min(r,sg[L(id)].r),L(id));
43 if(r>=sg[R(id)].l) query(max(l,sg[R(id)].l),r,R(id));
44 }
45 }
46 void init(){
47 memset(num,0,sizeof(num));
48 }

 

题目: poj  3468

 

参考文献 :http://kenby.iteye.com/blog/954112

posted @ 2012-02-29 16:44  HaoHua_Lee  阅读(165)  评论(0编辑  收藏  举报