对于单点更新,区间查询,更喜欢用树状数组解。
BIT二叉索引树,树状数组版
//代码贴上去时,有时前后会有一个html标签,删了
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#define N 50007
inline int lowbit(int x) {
return x & (-x);
}
int bit[N], n, a[N];
void add(int pos, int val) {
while (pos <= n) {
bit[pos] += val;
pos += lowbit(pos);
}
}
int sum(int pos) {
int res = 0;
while (pos > 0) {
res += bit[pos];
pos -= lowbit(pos);
}
return res;
}
int main()
{
int T, kase = 0;
scanf("%d", &T);
while (T--) {
printf("Case %d:\n", ++kase);
memset(bit, 0, sizeof bit);
memset(a, 0, sizeof a);
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
add(i, a[i]);
}
char opt[10];
int x, y;
while (~scanf("%s", opt)) {
if (!strcmp(opt, "End"))
break;
scanf("%d%d", &x, &y);
if (opt[0] == 'A') {
add(x, y);
}
else if (opt[0] == 'S') {
add(x, -1 * y);
}
else if (opt[0] == 'Q') {
printf("%d\n", sum(y) - sum(x - 1));
}
}
}
return 0;
}
\
线段树版
//线段树单点更新,区间查询。本题线段树srcTree存区间和
#include <cstdio>
#include <cstring>
#define N 50007
int n, secTree[N << 2];
void build(int rt, int l, int r) {
if (l == r) {
scanf("%d", secTree + rt);
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
secTree[rt] = secTree[rt << 1] + secTree[rt << 1 | 1];
}
void update(int rt, int l, int r, int pos, int inc) {
//根root, root所在区间[left, right], pos位置增加inc
if (l == r) {
secTree[rt] += inc; //也可以用一个数组存ary[N],为了省空间,secTree = ary[cur++]
return;
}
int mid = l + r >> 1;
if (pos <= mid)
update(rt << 1, l, mid, pos, inc);
else
update(rt << 1 | 1, mid + 1, r, pos, inc);
secTree[rt] = secTree[rt << 1] + secTree[rt << 1 | 1];
}
int query(int rt, int l, int r, int L, int R) {
//在(left, right)中查询 L , R (L, R)待查询区间
if (L <= l && r <= R) {
return secTree[rt];
}
int mid = l + r >> 1;
int ans = 0;
if (L <= mid)
ans += query(rt << 1, l, mid, L, R);
if (R > mid)
ans += query(rt << 1 | 1, mid + 1, r, L, R);
return ans;
}
int main()
{
int T, kase = 0;
scanf("%d", &T);
while(T-- > 0) {
memset(secTree, 0, sizeof secTree);
printf("Case %d:\n", ++kase);
scanf("%d", &n);
build(1, 1, n);
char cmd[10];
while(~scanf("%s", cmd) && strcmp(cmd, "End")) {
int a, b;
scanf("%d%d", &a, &b);
if (!strcmp(cmd, "Query")) {
printf("%d\n", query(1, 1, n, a, b));
}
else if (!strcmp(cmd, "Add")) {
update(1, 1, n, a, b);
}
else if (!strcmp(cmd, "Sub")) {
update(1, 1, n, a, -b);
}
}
}
return 0;
}
\
附:
树状数组还可用于二维的面修改查询操作
poj1195
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAX 1100
int C[MAX][MAX];
inline int lowbit(int x) {
return (x & (-x));
}
int s;
void add(int y, int x, int val) {
for (int i = y; i <= s; i += lowbit(i))
for (int j = x; j <= s; j += lowbit(j))
C[i][j] += val;
}
int sum(int y, int x) { //二维线段树小心宽和高可能不一样,不一定是n,我刚在poj2029栽了个跟头
//询问矩阵(1,1):(y,x)中元素的和
int res = 0;
for (int i = y; i > 0; i -= lowbit(i))
for (int j = x; j > 0; j -= lowbit(j))
res += C[i][j];
return res;
}
int main()
{
int cmd, y, x, val;
while (~scanf("%d", &cmd) && cmd != 3) {
switch (cmd) {
case 0:
scanf("%d", &s);
memset(C, 0, sizeof C);
break;
case 1:
scanf("%d%d%d", &x, &y, &val);
add(y + 1, x + 1, val);
break;
case 2:
int l, b, r, t;
scanf("%d%d%d%d", &l, &b, &r, &t);
l++, b++, r++, t++;
printf("%d\n", sum(t, r) - sum(b - 1, r) - sum(t, l - 1) + sum(b - 1, l - 1));
break;
}
}
return 0;
}
CSDN一天最多贴5篇\
\
\
\
\