題目大意:給定初始n*n矩陣,所有數都是0,然後有『c』操作:對左上角(x1,y1)到右下角(x2,y2)的矩陣中所有數取非,即0變1,或1變0;還有『q』操作:查詢點(x,y)的值並輸出。
思路:構造乙個線段樹,每個結點還是線段樹,外圍線段樹表示x方向,子線段樹表示y方向。查詢時對結點(x,y)所在的所有矩陣的值累計,這是因為在更新時,只更新到給定的矩陣(x1,x2,y1,y2),而對於這個矩陣中的點(x,y)則沒有更新,而演算法中沒有懶操作,故查詢時需將線段樹中經過的每個矩陣都進行計算,以達到懶操作的功能。
**如下:
#include #include #include #include #include #include #include using namespace std;
#define lson rt<<1
#define rson rt<<1|1
#define n 1005
struct snode
;struct node
st[4*n];
int ans;
void build_sub(snode sst,int rt,int ly,int ry)
void build(int rt,int lx,int rx,int ly,int ry)
void update_sub(snode sst,int rt,int y1,int y2)
int mid=(sst[rt].ly+sst[rt].ry)>>1;
if (y1<=mid) update_sub(sst,lson,y1,y2);
if (y2>mid) update_sub(sst,rson,y1,y2);
}void update(int rt,int x1,int y1,int x2,int y2)
int mid=(st[rt].lx+st[rt].rx)>>1;
if (x1<=mid) update(lson,x1,y1,x2,y2);
if (x2>mid) update(rson,x1,y1,x2,y2);
}void query_sub(snode sst,int rt,int y)
void query(int rt,int x,int y)
int main()
else
}printf("\n");}}
return 0;
}
另外有一種二維樹狀陣列的實現方式,比較容易寫,也容易理解些。
如果是在一維的樹狀陣列,在[l,r]的區間內進行翻轉操作後,我們把c[l]++;c[r+1]- -,這樣每乙個sum[x]記錄的就是這個點所進行翻轉的次數,次數為
奇數是該點值為1,次數為偶數時該點值為0。
同理可以擴充套件到二維的樹狀陣列中
**如下
#include #include #include #include using namespace std;
const int m = 1005;
int c[m][m];
int lowbit(int x)
void init();
void sol(int t);
void change(int x,int y,int d);
int sum(int x,int y);
int result(int x,int y,int a,int b);
int main()
return 0;
}void init()
void sol(int t)
else
}return;
}void change(int x,int y,int d)
int sum(int x,int y)
int result(int x,int y,int a,int b)
POJ 2155 二維線段樹
題意 給乙個01矩陣,每次可以進行操作將 x1,x2,y1,y2 內的所有元素0變1 1變0。也可以進行詢問,詢問某乙個格仔的0和1。輸出詢問。思路 二維線段樹版題,稍微轉化一下記錄查詢乙個點時它所經過的路徑上經過偶數次修改就為0,奇數次為1。線段樹有兩種寫法,第一種把下標放在樹的結點中,時不時會m...
二維線段樹 poj 2155
題意 t組樣例 輸入 n,m,表示n n的矩陣進行m次操作 c 輸入兩個座標 組成的矩形 進行取反操作 q 對輸的座標位置輸入其值。思路 一開始想的是用1000 表示x軸 個線段樹 對每段y進行操作 來記錄,也是二維的 第一維暴力 第二維線段樹 結果ti 原來還有二維線段樹,每個對應的節點都有一顆線...
poj 2155 二維線段樹
在乙個二維陣列中,每次對乙個矩形內所有資料進行取反操作,並實時詢問某一位置的值。一般線段樹只支援對一維資料進行更新和查詢,但是這題給的是二維資料啊!這裡就需要用到二維線段樹了,即樹套樹,外層線段樹的每個結點裡面都有一顆線段樹。在實現二維線段樹的時候,一開始用加build函式的方式,記錄每個結點左右孩...