POJ2155 Matrix 二維樹狀數組應用,poj2155matrix
一個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。
題目乍一看感覺還是很難,如果能記錄每一個元素的狀態值,那答案是顯而易見的,但是元素過多,如果每次都對每一個元素進行更新狀態的話,複雜度太高。實際上只要記錄邊界的特定座標的反轉次數,最好的選擇那就是二維樹狀數組了。
對於操作C,為了保證元素在子矩陣內的反轉次數都增加了1,需要在(x1,y1)的位置上加上1,(x2 + 1, y1) 減去1,(x1, y2 + 1)減去1,(x2 +1, y2 + 1)加上1;
對於操作Q,直接擷取Bit(x,y) 的值就代表該元素反轉了多少次。
#include <stdlib.h>#include <stdio.h>#include <vector>#include <math.h>#include <string.h>#include <string>#include <iostream>#define MAXN 1001template <class TYPE>void BITAdd(TYPE array[MAXN], int i, TYPE addvalue, int n){while (i <= n){array[i] += addvalue;i += i & -i;}}template <class TYPE>TYPE BITGet(TYPE array[MAXN], int i){TYPE ss = 0;while (i > 0){ss += array[i];i -= i & -i;}return ss;}template <class TYPE>void BIT2DAdd(TYPE array[MAXN][MAXN], int i, int j,TYPE addvalue, int n, int m){while (i <= n){BITAdd<TYPE>(array[i], j, addvalue, m);i += i & -i;}}template <class TYPE>TYPE BIT2DGet(TYPE array[MAXN][MAXN], int i, int j){TYPE ss = 0;while (i > 0){ss += BITGet<TYPE>(array[i], j);i -= i & -i;}return ss;}typedef int MYTYPE;MYTYPE Bit[MAXN][MAXN];int main(){#ifdef _DEBUGfreopen("d:\\in.txt", "r", stdin);#endifint x;scanf("%d", &x);for (int i = 0; i < x; i++){memset(Bit, 0, sizeof(Bit));int n, k;scanf("%d %d\n", &n, &k);if (i >= 1){printf("\n");}for (int j = 0; j < k; j++){char ope;scanf("%c", &ope);if (ope == 'C'){int x1, x2, y1, y2;scanf("%d %d %d %d\n", &x1, &y1, &x2, &y2);BIT2DAdd<int>(Bit, x1, y1, 1, n, n);BIT2DAdd<int>(Bit, x2 + 1, y1, -1, n, n);BIT2DAdd<int>(Bit, x1, y2 + 1, -1, n, n);BIT2DAdd<int>(Bit, x2 + 1, y2 + 1, 1, n, n);}else{int x, y;scanf("%d %d\n", &x, &y);int thisvalue = BIT2DGet<int>(Bit, x, y);printf("%d\n", thisvalue & 1);}}}return 0;}
二維樹狀數組中數組記錄的是什?
那個lowbit可以改成t&(-t)
你這個是不是寫錯了?
temp+=lowbit(temp);
i+=lowbit(i);
吧
在1維裡c[i]代表 從i開始到它前面一個lowbit之間的和值
c[i]=sum(a[x],i-lowbit(i)<=x<=i);
想象一個矩陣,相當於
c[i][j]=sum(a[x][y],i-lowbit(i)<=x<=i
j-lowbit(j)<=y<=j)
而且我不知道你這樣寫可以不。。。
樹狀數組的其他功可以
修改區間值可以,但是這樣就不能求區間和了(只能求一個點),poj上的matrix是個很好的例子,代碼在最後
區間最小值:如果是單端點(從1到r)或者是 雙端點(l和r)但是靜態就可以,雙端點lg^2 n,原理是區間逼近
你也可以在樹樁數組裡實現lazy-tag,就是不一般的麻煩,我還沒調過
Code:(我寫麻煩了)
修改整個區間的值(一維度):
#include <cstdio>
#include <cstring>
using namespace std;
int n,c[1000005];
void chg_org(int i,int delta) {
while (i<=n) {
c[i]+=delta;
i+=i&(-i);
}
}
int qry_org(int i) {
int ret=0;
while (i>0) {
ret+=c[i];
i-=i&(-i);
}
return ret;
}
void chg_itvl(int l,int r) {
chg_org(l,1);
chg_org(r+1,-1);
}
int qry_elem(int x) {
return qry_org(x);
}
int main() { //a sample:p2155,1-dimension
scanf("%d",&n);
memset(c,0,sizeof c);
int m,k,xx;
scanf("%d",&m);
for (int i=0;i<m;++i) {
scanf("%d%d",&k,&xx);
if (k>0)
chg_itvl(k,xx);
else
printf("%d\n",qry_elem(xx)%2);
}
return 0;
}
區間最小值:我把它和傳統的方在一起了
{basic_structure->statistics->binary index tree}
{
the insert,query_sum function are for sum,they work dynamically.
the prep_rmq,query_min function are for rmq,they work statically only.
}
var
sum:array [1..10000000] of int64;
min:array [1..10000000] of longint;//only static avaliable
a:array [1..10000000] of longint;
n,i,t,m,q1,q2,l,r:longint;
procedure insert(i:longint;key:longint);
//only maintain the sum field
var dx:longint;
begin
dx:=key-a[i];
a[i]:=key;
while (i<=n) do
begin
inc(sum[i],dx);
inc(i,i and (-i));
end;
end;
fu......餘下全文>>