HLJU 1188 Matrix (二維樹狀數組)
Matrix
Time Limit: 4 Sec Memory Limit: 128 MBDescription
給定一個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 (二維樹狀數組)