HDU 1892 See you~(二维树状数组的单点更新,区间求值)

题目链接:点击打开链接

二维树状数组单点更新,区间求值的入门题目:

一维树状数组的思想很容易应用到二维树状数组中,sum[i][j]表示一块矩阵的和,其中i - lowBit(i) < x <= i,j - lowBit(j) < y <= j。

那么求以(x1,y1) (左下角) 和 (x2,y2)(右上角) 为对角线的矩阵的和为getSum(x2,y2) - getSum(x1 - 1,y2) - getSum(x2,y1 - 1) + getSum(x1 - 1,y1 - 1)。

// HDU 1892 See you~.cpp 运行:1248ms
#include "stdafx.h"
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int sum[1005][1005];
int lowBit(int x) {
	return x & (-x);
}
void update(int x, int y, int n) {
	for (int i = x; i < 1005; i += lowBit(i)) {
		for (int j = y; j < 1005; j += lowBit(j)) {
			sum[i][j] += n;
		}
	}
}
int getSum(int x, int y) {
	int re = 0;
	for (int i = x; i > 0; i -= lowBit(i)) {
		for (int j = y; j > 0; j -= lowBit(j)) {
			re += sum[i][j];
		}
	}
	return re;
}
int getValue(int x, int y) {//单点更新,区间求值的树状数组也可以单点求值
	return getSum(x, y) - getSum(x - 1, y) - getSum(x, y - 1) + getSum(x - 1,y - 1);
}
void init() {
	memset(sum, 0, sizeof(sum));
	for (int i = 1; i < 1005; i++) {
		for (int j = 1; j < 1005; j++) {
			update(i, j, 1);
		}
	}
}
int main(){
	int k,m;
	int x1, y1, x2, y2, n1;//题目给的坐标为从0计数,树状数组需要从下标1开始计数,因此操作时需要转换一下
	int x11, y11, x22, y22, value;
	scanf("%d", &k);
	for(int i = 1;i <= k;i++){
		scanf("%d", &m);
		printf("Case %d:\n", i);
		init();
		for (int j = 0; j < m; j++) {
			getchar();
			char ch = getchar();
			switch (ch) {
			case 'S':
				scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
				x11 = max(x1, x2);
				x22 = min(x1, x2);
				y11 = max(y1, y2);
				y22 = min(y1, y2);
				printf("%d\n", getSum(x11 + 1, y11 + 1) - getSum(x22, y11 + 1) - getSum(x11 + 1, y22) + getSum(x22, y22));
				break;
			case 'A':
				scanf("%d%d%d", &x1, &y1, &n1);
				update(x1 + 1, y1 + 1, n1);
				break;
			case 'D':
				scanf("%d%d%d", &x1, &y1, &n1);
				value = getValue(x1 + 1,y1 + 1);
				n1 = min(value, n1);
				update(x1 + 1, y1 + 1, -n1);
				break;
			case 'M':
				scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &n1);
				value = getValue(x1 + 1, y1 + 1);
				n1 = min(value, n1);
				update(x1 + 1, y1 + 1, -n1);
				update(x2 + 1, y2 + 1, n1);
				break;
			}
		}
	}
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值