1. 程式人生 > >淺顯易懂的標記永久化講解 && POI 2006 Tet-Tetris 3D | 二維線段樹

淺顯易懂的標記永久化講解 && POI 2006 Tet-Tetris 3D | 二維線段樹

記錄 變量 digi 查詢 今天 class .org ring post

題目:Luogu 3437

這是今天 SLYZ 考試的一道題,一道二維線段樹的入門題,慘的是我之前沒有寫過二維線段樹,更不知道什麽是標記用久化,於是自己 YY 出了標記永久化,但由於我十分的菜所以寫炸了。

如果按照普通線段樹的方法來做,發現外層的 x 樹是無法 pushdown 和 maintain 的,怎麽辦?

如果遇到無法下傳標記的情況,大概就要用到標記永久化了。

所謂標記永久化,就是不下傳標記,查詢時路過該節點,就加上這個節點的標記。

1. 如何省去 maintain 操作

用數組 val[ ] 來記錄一個節點的值。

在 update 之前,先 query 出將要更新的節點的原值,設變量 value 為這個原值加上要加的值,然後 update。

update 時,沿路用 value 更新路過的節點,每到達一個節點,val[cur] = max(val[cur], value);

這就相當於 maintain 的時候用左右兒子節點更新當前節點。

2. 如何省去 pushdown 操作

用數組 tag[ ] 記錄永久化的標記。

在 update 中,若到達了目標節點(Ql <= l && r <= Qr),需要用 value 更新當前節點的 tag,即 tag[cur] = max(tag[cur], value);

這一步有什麽用呢?

在 query 的時候,若路過一個節點,需要將它的 tag 加入計算。如下圖。

技術分享圖片

假如之前更新過 3 號和 5 號點,則 val[1]、val[2]、val[3]、val[5] 都有變動,並且 tag[1] 和 tag[3] 處有標記。

此時若要查詢 4 號點和 6 號點的值:

查詢 4 號點,由於 tag[1] 和 tag[2] 為空,所以答案為 val[4];

查詢 6 號點,3 號點的標記按理說應該下傳,但我們不下傳,所以答案為 max(tag[3], val[6]);

詳見代碼。

 1 #include <cstdio>
 2 #include <string>
 3 
 4 int read() {
 5
int x = 0, f = 1; 6 char c = getchar(); 7 while (!isdigit(c)) { 8 if (c == -) f = -1; 9 c = getchar(); 10 } 11 while (isdigit(c)) { 12 x = (x << 3) + (x << 1) + (c ^ 48); 13 c = getchar(); 14 } 15 return x * f; 16 } 17 18 int max(int x, int y) { 19 if (x >= y) return x; return y; 20 } 21 22 const int N = 4005; int D, S; 23 24 struct inNode { 25 int val[N], tag[N]; 26 void update(int cur, int l, int r, int y1, int y2, int value) { 27 val[cur] = max(val[cur], value); 28 if (y1 <= l && r <= y2) { 29 tag[cur] = max(tag[cur], value); 30 } else { 31 int mid = l + ((r - l) >> 1); 32 if (y1 <= mid) update(cur << 1, l, mid, y1, y2, value); 33 if (mid < y2) update(cur << 1 | 1, mid + 1, r, y1, y2, value); 34 } 35 } 36 37 int query(int cur, int l, int r, int y1, int y2) { 38 if (y1 <= l && r <= y2) return val[cur]; 39 int mid = l + ((r - l) >> 1), res = tag[cur]; 40 if (y1 <= mid) res = max(res, query(cur << 1, l, mid, y1, y2)); 41 if (mid < y2) res = max(res, query(cur << 1 | 1, mid + 1, r, y1, y2)); 42 return res; 43 } 44 }; 45 46 struct outNode { 47 inNode val[N], tag[N]; 48 void update(int cur, int l, int r, int x1, int x2, int y1, int y2, int value) { 49 val[cur].update(1, 1, S, y1, y2, value); 50 if (x1 <= l && r <= x2) { 51 tag[cur].update(1, 1, S, y1, y2, value); 52 } else { 53 int mid = l + ((r - l) >> 1); 54 if (x1 <= mid) update(cur << 1, l, mid, x1, x2, y1, y2, value); 55 if (mid < x2) update(cur << 1 | 1, mid + 1, r, x1, x2, y1, y2, value); 56 } 57 } 58 59 int query(int cur, int l, int r, int x1, int x2, int y1, int y2) { 60 if (x1 <= l && r <= x2) return val[cur].query(1, 1, S, y1, y2); 61 int mid = l + ((r - l) >> 1), res = tag[cur].query(1, 1, S, y1, y2); 62 if (x1 <= mid) res = max(res, query(cur << 1, l, mid, x1, x2, y1, y2)); 63 if (mid < x2) res = max(res, query(cur << 1 | 1, mid + 1, r, x1, x2, y1, y2)); 64 return res; 65 } 66 } tree; 67 68 int main() { 69 D = read(), S = read(); int n = read(); ++ D, ++ S; 70 for (int i = 1; i <= n; ++ i) { 71 int d = read(), s = read(), w = read(), 72 x = read(), y = read(); ++ x, ++ y; 73 int tmp = tree.query(1, 1, D, x, x + d - 1, y, y + s - 1); 74 tree.update(1, 1, D, x, x + d - 1, y, y + s - 1, tmp + w); 75 } 76 printf("%d\n", tree.query(1, 1, D, 1, D, 1, S)); 77 return 0; 78 }

淺顯易懂的標記永久化講解 && POI 2006 Tet-Tetris 3D | 二維線段樹