线段树模板1

已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和

即支持区间修改(区间加)和区间查询。

(这里的修改顺序对结果无影响)

代码如下:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=200010;
int m, n, f, a[maxn];
long long sumv[maxn<<2], addv[maxn<<2];

void build_tree(int o, int L, int R) {
    if (L==R) addv[o]=sumv[o]=a[L];
    else {
        int M=L+((R-L)>>1);
        int lc=(o<<1), rc=((o<<1)+1);
        build_tree(lc, L, M);
        build_tree(rc, M+1, R);
        sumv[o]=sumv[lc]+sumv[rc];
    }
    return;
}

int yl, yr;
long long query(int o, int L, int R, long long add) {
    if (yl<=L && R<=yr) return sumv[o]+add*(R-L+1);
    int M=L+((R-L)>>1);
    long long sum=0;
    int lc=(o<<1), rc=((o<<1)+1);
    if (yl<=M) sum+=query(lc, L, M, add+addv[o]);
    if (yr>M) sum+=query(rc, M+1, R, add+addv[o]);
    return sum;
}

void maintain(int o, int L, int R) {
    int lc=(o<<1), rc=((o<<1)+1);
    sumv[o]=addv[o]*(R-L+1);
    if (R>L) sumv[o]+=sumv[lc]+sumv[rc];
    return;
}

int ql, qr;
int v;
void update(int o, int L, int R) {
    if (ql<=L && R<=qr) addv[o]+=v;
        else {
            int M=L+((R-L)>>1);
            int lc=(o<<1), rc=((o<<1)+1);
            if (ql<=M) update(lc, L, M);
            if (qr>M) update(rc, M+1, R);
      }
      maintain(o, L, R);
    return;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n; i++) scanf("%d", &a[i]);
    build_tree(1, 1, n);
    while (m--){
        scanf("%d", &f);
        if (f==1) {
            scanf("%d%d%d", &ql, &qr, &v);
            update(1, 1, n);
        } else {
            scanf("%d%d", &yl, &yr);
            printf("%lld
",query(1, 1, n, 0));
        }
    }
    return 0;
}

 题目见洛谷P3372

(貌似也可以用分块和树状数组水过的样子,虽然我暂时并不知道树状数组是怎么做到的(嗯,以后一定会学的))

因为数据范围long long的问题一直70分....

原文地址:https://www.cnblogs.com/zjzj/p/7043900.html