线段树-区间查询模版
/* *模版原题:PKU 3468 *线段树 *区间求和 */ #include <cstdio> #include <algorithm> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 #define LL __int64 const int maxn = 111111; LL add[maxn<<2]; LL sum[maxn<<2]; //回溯更新父节点 void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } //延迟操作 //此为成段加减算法。 //rt为该点下标;m为该点区间范围大小 void PushDown(int rt,int m) { if (add[rt]) { //成段加,故为+= //同理可改为 -= max() min() change() add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; sum[rt<<1] += add[rt] * (m - (m >> 1)); // sum[rt*2]+=( add值*其旗下最终子节点个数); sum[rt<<1|1] += add[rt] * (m >> 1); // 同上 add[rt] = 0; } } //建立线段树 //当前节点包含的范围lr;以及该节点的下标rt void build(int l,int r,int rt) { add[rt] = 0; //清空操作 if (l == r) { scanf("%lld",&sum[rt]); return ; } int m = (l + r) >> 1; build(lson); //l , m , rt << 1 build(rson); PushUp(rt); } //成段更新 //在L和R区间内每个数分别加上c; void update(int L,int R,int c,int l,int r,int rt) { if (L <= l && r <= R) //查询 { add[rt] += c; //储存更新操作,占时不对子节点进行操作 sum[rt] += (LL)c * (r - l + 1); return ; } PushDown(rt , r - l + 1); //对之前延时更新进行对应处理 int m = (l + r) >> 1; if (L <= m) update(L , R , c , lson); if (m < R) update(L , R , c , rson); PushUp(rt); } //范围求和。 //L 和R为输入的查询范围 LL query(int L,int R,int l,int r,int rt) { if (L <= l && r <= R) { return sum[rt]; } PushDown(rt , r - l + 1); int m = (l + r) >> 1; LL ret = 0; if (L <= m) ret += query(L , R , lson); if (m < R) ret += query(L , R , rson); return ret; } int main() { int N , Q; scanf("%d%d",&N,&Q); build(1 , N , 1); while (Q--) { char s[2]; int a , b , c; scanf("%s",s); if (s[0] == 'Q') { scanf("%d%d",&a,&b); printf("%lld\n",query(a , b , 1 , N , 1)); } else { scanf("%d%d%d",&a,&b,&c); update(a , b , c , 1 , N , 1); } } return 0; }