单点更新 “区间和”最值查询 线段树解法 和 BIT解法 杭电hdu1166-CSDN博客

57 阅读1分钟

对于单点更新,区间查询,更喜欢用树状数组解。

hdu1166 敌兵布阵 

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篇\

\

\

\

\