线段树之单点修改、区间求和的模板

#include 
using namespace std;

/*
    第一行n, m, 表示数的个数以及操作数
    第二行表示n个数
    剩下m行, 每行x, y, z表示操作(1:表示将第y个数加z; 2:求[y, z]区间和)

    用线段树, 下面是线段数的模板(单点修改, 区间求和)
*/

int n, m;
int ans = 0;
int he = 0; // 表示线段数中的节点数
int input[500010];

struct node {
    int l, r, n;
}tree[2000010];


void build(int l, int r, int idx) {     //构建线段树, 填充[l, r]之间的节点, 每一个节点记录的是一个区间的左界与右界
    he++;
    tree[idx].l = l;                
    tree[idx].r = r;

    if(l == r)  return;

    int mid = l + r >> 1;
    build(l, mid, idx << 1);     //递归求下一层的区间, 以中间点为界限分为左右两个区间
    build(mid + 1, r, (idx << 1) + 1);
}

int add(int idx) {     //填充线段树, 将待处理数据填入线段树
    if(tree[idx].l == tree[idx].r) {
        tree[idx].n = input[tree[idx].l];
        return tree[idx].n;
    }
    tree[idx].n = add(idx << 1) + add((idx << 1) + 1);
    return tree[idx].n;
}

void my_plus(int cur, int idx, int k) {     //单点修改, cur表示当前的节点, idx表示需要修改的节点
    tree[cur].n += k;

    if(tree[cur].l == tree[cur].r)  return;     //修改到最后的单点区间了, 即所有需要修改的区间修改完毕

    if(idx <= tree[cur << 1].r) {
        my_plus(cur << 1, idx, k);
    }

    if(idx >= tree[(cur << 1) + 1].l) {
        my_plus((cur << 1) + 1, idx, k);
    }
}

void search(int idx, int l, int r) {     //[l, r]区间求和
    if(tree[idx].l >= l &&  tree[idx].r <= r) {    
        ans += tree[idx].n;
        return;
    }

    if(tree[(idx << 1) + 1].l <= r) {
        search((idx << 1) + 1, l, r);
    }
    
    if(tree[idx << 1].r >= l) {
        search(idx << 1, l, r);
    }

}

int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> input[i];
    build(1, n, 1);
    add(1);

    while(m--) {
        int x, y, z;
        cin >> x >> y >> z;
        if(x == 1) {
            my_plus(1, y, z);
        }
        if(x == 2) {
            ans = 0;
            search(1, y, z);
            cout << ans << endl;
        }
    }
    return 0;
}

你可能感兴趣的:(算法,c++,数据结构)