线段树 区间更新 区间求和 板子

poj 3468

给出N个数,Q次操作。有两种操作类型

1. 在区间 [L,R] 加上一个整数v

2. 区间[L,R]查询。

区间查询 区间更新

#include<iostream>
#include<string.h>
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
typedef long long ll;
const int N = 1e5+10;
int n,q,num[N];
ll tr[N<<2],lz[N<<2];

void down(int rt,int l,int r) {
    if(lz[rt]) {
        int m = (l+r)/2;
        lz[ls] += lz[rt];
        lz[rs] += lz[rt];
        tr[ls] += 1LL*(m-l+1)*lz[rt];
        tr[rs] += 1LL*(r-m)*lz[rt];
        lz[rt] = 0;
    }
}

void build(int rt,int l,int r) {
    if(l == r){
        tr[rt]=num[l];
        return ;
    }
    int m = (l+r)/2;
    build(ls,l,m);
    build(rs,m+1,r);
    tr[rt] = tr[ls] + tr[rs];
}
void update(int rt,int l,int r,int L,int R,int x) {
    if(L <= l && r <= R) {
        lz[rt] += x;
        tr[rt] += 1LL*(r-l+1)*x;
        return ;
    }
    down(rt,l,r);
    int m=(l+r)/2;
    if(m >= L)
        update(ls,l,m,L,R,x);
    if(m < R)
        update(rs,m+1,r,L,R,x);
    tr[rt] = tr[ls] + tr[rs];
}
ll query(int rt,int l,int r,int L,int R) {
    if(L <= l && r <= R) {
        return tr[rt];
    }
    down(rt,l,r);
    ll res = 0;
    int m=(l+r)/2;
    if(m >= L)
        res += query(ls,l,m,L,R);
    if(m < R)
        res += query(rs,m+1,r,L,R);
    return res;
}

int main () {
    //freopen("in.txt","r",stdin);
    while (scanf("%d %d",&n,&q)==2) {
        for(int i=1;i<=n;i++) {
            scanf("%d",&num[i]);
        }
        memset(lz,0,sizeof(lz));
        build(1,1,n);
        while (q--) {
            char op[3];
            int L,R;
            scanf("%s %d %d",op,&L,&R);
            if(op[0]=='Q') {
                printf("%lld
",query(1,1,n,L,R));
            }else {
                int x; scanf("%d",&x);
                update(1,1,n,L,R,x);
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Draymonder/p/9478127.html