HLJU 1188 Matrix (二维树状数组)

Matrix

Time Limit: 4 Sec  Memory Limit: 128 MB

Description

给定一个1000*1000的二维矩阵,初始矩阵中每一个数都为1,然后为矩阵有4种操作.

S x1 y1 x2 y2:计算(x1,y1)、(x2,y2)围成的矩阵内全部元素的和。

A x y v:将(x,y)添加v

D x y v:将(x,y)降低v

M x1 y1 x2 y2 v:将(x1,y1)元素中的v转移到(x2,y2)中去。

全部操作数都为正数。

若某一操作将矩阵中元素降到1下面,一律按1处理。

x,y从0開始编号。

Input

第一行一个数t,代表例子个数:

每组例子第一行一个数m,代表m次操作,m<100000

接下来m行代表m次操作

Output

每组例子输出一个

Case i:

i代表第i个例子

对于每个操作S,输出一行,代表计算结果。

全部结果均不会超过int范围

Sample Input

1
4
A 1 1 1
M 1 1 2 2 1
D 2 2 1
S 1 1 2 2

Sample Output

Case 1:
4

解题思路:非常明显的就是一个非常典型的二维树状数组问题,树状数组部分全然就是模板,仅仅是要在详细解决实际问题的时候,有点技巧。最開始见到这题的时候,我马上想到了曾经切的楼教主出的Matrix,感觉非常相似。然后就直接搞了,后来发现開始,要初始化树状数组的c数组,由于矩阵的初值均为1。就用了两层循环。一个一个调用update()。结果居然超时了。

。然后又在其它地方优化了,还是超时。。。

就想了个办法。直接把c数组所有初始化为0。这样就不用一次次的去调用update()了(由于c要存的是他前面的和,如今全为0,和当然也为0了),然后在求区域和的时候。直接加上那个区间里的节点数(由于本来的矩阵中应该所有初始化为1的,可是我開始全初始化为0了。就把每一个节点都少了1,节点数也就是区间的面积)就可以。

还有就是要求保证原矩阵元素在操作之后不能小于1。详细能够先算出当前位置的元素值,
在操作之前把操作的数e改动。然后直接运行操作就可以。这里还学到了一个求当前位置元素的方法,直接用区域求和函数,对当前点求和。即map[a][b] = getsum( a, b, a, b ). 详见代码

楼教主的Matrix 见:http://blog.csdn.net/u013446688/article/details/38194977

AC代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1002;

#define lowbit(x)	x & (-x)       //lowbit函数            

int c[maxn][maxn];                     //树状数组的c数组

inline int update(int x, int y, int d){      //update函数
	int i, j;
	for(i=x; i<=1000; i+=lowbit(i))
		for(j=y; j<=1000; j+=lowbit(j))
			c[i][j] += d;
}

inline int sum(int x, int y){         //sum函数
	int ans = 0;
	int i, j;
	for(i=x; i>0; i-=lowbit(i))
		for(j=y; j>0; j-=lowbit(j))
			ans += c[i][j];
	return ans;
}

int getsum(int x1, int y1, int x2, int y2){       //区域求和
	return  sum(x2, y2) - sum(x1-1, y2) - sum(x2, y1-1) + sum(x1-1, y1-1);
}

int main(){
//	freopen("in.txt","r",stdin);
	int T, m ,a, b, cc, d, e;
	string p;
	scanf("%d", &T);
	for(int t=1; t<=T; t++){
		scanf("%d", &m);
		printf("Case %d:\n", t);
		memset(c, 0, sizeof(c));
		while(m--){
			cin>>p;
			if(p[0] == ‘A‘){
				scanf("%d%d%d", &a, &b, &e);
				a++; b++;
				update(a, b, e);
			}
			else if(p[0] == ‘D‘){
				scanf("%d%d%d", &a, &b, &e);
				a++; b++;
				int k = getsum(a, b, a, b);      //求当前位置的元素的值
				if(k - e < 0)  e = k;            //改动e, 保证操作之后元素不小于1
				update(a, b, -e);
			}
			else if(p[0] == ‘M‘){
				scanf("%d%d%d%d%d", &a, &b, &cc, &d, &e);
				a++; b++; cc++; d++;
				int k = getsum(a, b, a, b);      //同上
				if(k - e < 0)   e = k;
				update(a, b, -e);

				update(cc, d, e);
			}
			else{
				scanf("%d%d%d%d", &a, &b, &cc, &d);
				a++; b++; cc++; d++;
				if(cc < a)  swap(a, cc);
				if(d < b)  swap(b, d);
				int ans = getsum(a, b, cc, d) + (cc-a+1)*(d-b+1);    //求矩阵区域和
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}
时间: 2024-08-26 20:47:15

HLJU 1188 Matrix (二维树状数组)的相关文章

POJ2155 Matrix 二维树状数组的应用

有两种方法吧,一个是利用了树状数组的性质,很HDU1556有点类似,还有一种就是累加和然后看奇偶来判断答案 题意:给你一个n*n矩阵,然后q个操作,C代表把以(x1,y1)为左上角到以(x2,y2)为右下角的矩阵取反,意思就是矩阵只有0,1元素,是0的变1,是1的变0,Q代表当前(x,y)这个点的状况,是0还是1? 区间修改有点特别,但是若区间求和弄懂了应该马上就能懂得: add(x2,y2,1); add(x2,y1,-1);//上面多修改了不需要的一部分,所以修改回来 add(x1,y2,-

Matrix 二维树状数组的第二类应用

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17976   Accepted: 6737 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ 2155 Matrix(二维树状数组,绝对具体)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

[poj2155]Matrix(二维树状数组)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 25004   Accepted: 9261 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ 2155 Matrix(二维树状数组,绝对详细)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ2155 Matrix 二维树状数组应用

一个N*N(1<=N<=1000)的矩阵,从(1,1)开始,给定一些操作C和一些查询Q,一共K条(1<=K<=50000): C x1,y1,x2,y2 表示从x1行y1列到x2行y2列的元素全部反转(0变成1,1变成0): Q x y表示询问x行y列的元素是0还是1. 题目乍一看感觉还是很难,如果能记录每一个元素的状态值,那答案是显而易见的,但是元素过多,如果每次都对每一个元素进行更新状态的话,复杂度太高.实际上只要记录边界的特定坐标的反转次数,最好的选择那就是二维树状数组了.

POJ 2155 Matrix 二维树状数组

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 19174   Accepted: 7207 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ - 2155 Matrix (二维树状数组 + 区间改动 + 单点求值 或者 二维线段树 + 区间更新 + 单点求值)

POJ - 2155 Matrix Time Limit: 3000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we ha

Matrix (二维树状数组)

Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1 <= i, j <= N). We can change the matrix in the following way. Given a rectangle whose upp

POJ2155:Matrix(二维树状数组,经典)

Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1 <= i, j <= N). We can change the matrix in the following way. Given a rectangle whose upp