树状数组

一般用于单点修改,区间查询
模板:

const int N = 1e6 + 10;

int tree[N];

int lowbit(int x) {
    return x & -x;
}
void add(int x, int k) { // 修改
    while(x <= n) {
        tree[x] += k;
        x += lowbit(x);
    }
}
int find(int x) { // 查询
    int res = 0;
    while(x != 0) {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}

对于单点修改,区间查询的完整代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;

int tree[N];
int n, m;

int lowbit(int x) {
    return x & -x;
}
void add(int x, int k) {
    while(x <= n) {
        tree[x] += k;
        x += lowbit(x);
    }
}
int find(int x) {
    int res = 0;
    while(x != 0) {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}

int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) {
        int t;
        cin >> t;
        add(i, t);
    }
    for(int i = 1; i <= m; i ++) {
        int op;
        cin >> op;
        if(op == 1) {
            int x, k;
            cin >> x >> k;
            add(x, k);
        }
        else {
            int x, y;
            cin >> x >> y;
            cout << find(y) - find(x - 1) << endl;
        }
    }
    return 0;
}

例题:【模板】树状数组

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 5;

int m, n;
int c[N];

int lowbit(int x) {
	return x & -x;
}
int query(int x) {
	int res = 0;
	while(x) {
		res += c[x];
		x = x - lowbit(x);
	}
	return res;
}
void add_x(int x, int val) {
	while(x < N) {
		c[x] += val;
		x = x + lowbit(x);
	}
}

int main() {
    cin >> m >> n;
    for(int i = 1; i <= m; i ++) {
        int ans;
        cin >> ans;
        add_x(i, ans);
    }
    int a, x, y;
    while(n --) {
        cin >> a >> x >> y;
        if(a == 1) {
            add_x(x, y);
        }
        else if(a == 2) {
            cout << query(y) - query(x - 1) << endl;
        }
    }
    return 0;
}

而对于区间修改,单点查询的题,只需要运用前缀和与差分的知识做一点小修改即可。

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;

int tree[N], a[N];
int n, m;

int lowbit(int x) {
    return x & -x;
}
void add(int x, int k) {
    while(x <= n) {
        tree[x] += k;
        x += lowbit(x);
    }
}
int find(int x) {
    int res = 0;
    while(x != 0) {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}

int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
    }
    for(int i = 1; i <= m; i ++) {
        int op;
        cin >> op;
        if(op == 1) {
            int x, y, k;
            cin >> x >> y >> k;
            add(x, k); // 根据差分只需要让 tree[x] + k 即可保证区间的值都加上了k
            add(y + 1, - k); // 到区间右端时,只需让 tree[x + 1] - k 即可保证区间以后的值不改变 
        }
        else {
            int x;
            cin >> x;
            cout << find(x) + a[x] << endl; // 查询的值即为数组的前缀和
        }
    }
    return 0;
}
posted @ 2024-05-13 18:29  懒羊羊爱吃灰太狼  阅读(14)  评论(0)    收藏  举报