1. 程式人生 > >HLJU 1188 Matrix (二維樹狀數組)

HLJU 1188 Matrix (二維樹狀數組)

swap esp pad input family rom 其它 sdn else

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;
}


HLJU 1188 Matrix (二維樹狀數組)