题目描述
POJ 3468 A Simple Problem with Integers
解题思路
题目大意:
对给定的一段区间支持下列操作:
1) 对区间[l, r] 的所有数, 增加(或减少)某个值
2) 查询区间[l, r] 的和
线段树成段更新的类型题, 具体看注释~^ ^
参考代码
#include <stdio.h>
#define lson rt<<1
#define rson rt<<1|1
#define mid ((l+r) >> 1)
typedef __int64 ll;
const int MAX_N = 100010;
struct SegTree{
ll sum, add; // sum 是 区间的和, add 是延迟标记
}node[MAX_N << 2];
void pushup(int rt){
node[rt].sum = node[lson].sum + node[rson].sum;
}
// 延迟更新
void pushdown(int rt, int len){
if (node[rt].add){ // 如果根节点有延迟标记的话
node[lson].add += node[rt].add; // 左儿子加上延迟的值
node[rson].add += node[rt].add; // 右儿子加上延迟的值
// 每个区间的和 在原来的基础上 再加上 由于延迟产生的差值 = 区间长度 * 延迟的大小
node[lson].sum += (len - (len >> 1)) * node[rt].add;
node[rson].sum += (len >> 1) * node[rt].add;
node[rt].add = 0; // 因为已经释放下去了, 所以要去掉根节点的延迟标记
}
}
// 建树
void build(int l, int r, int rt){
node[rt].add = 0;
if (l == r){
scanf("%I64d", &node[rt].sum);
return ;
}
build(l, mid, lson);
build(mid+1, r, rson);
pushup(rt);
}
//区间更新
void update(int L, int R, int add, int l, int r, int rt){
int len = (r - l + 1);
if (L <= l && r <= R){
node[rt].add += add;
node[rt].sum += len * add;
return ;
}
pushdown(rt, len); // 释放延迟标记
if (L <= mid) update(L, R, add, l, mid, lson);
if (R > mid) update(L, R, add, mid+1, r, rson);
pushup(rt);
}
ll query(int L, int R, int l, int r, int rt){
int len = (r - l + 1);
if (L <= l && r <= R){
return node[rt].sum;
}
pushdown(rt, len); // 查询时也要释放延迟标记
ll ans = 0;
if (L <= mid) ans += query(L, R, l, mid, lson);
if (R > mid) ans += query(L, R, mid+1, r, rson);
pushup(rt);
return ans;
}
int main(){
int N, Q, x, y, z;
char c;
while (~scanf("%d %d", &N, &Q)){
build(1, N, 1);
while (Q--){
scanf(" %c %d %d", &c, &x, &y);
if (c == 'Q')
printf("%I64d\n", query(x, y, 1, N, 1));
else{
scanf("%d", &z);
update(x, y, z, 1, N, 1);
}
}
}
return 0;
}