數列分塊解決區間更新+區間最值問題
阿新 • • 發佈:2021-11-26
題目大意:
給定一個大小為 \(n\) 的數列 \(a_1, a_2, \ldots, a_n\),你需要對這個數列進行 \(m\) 次操作,操作包含如下兩種型別:
1 x y z
:將區間 \([x,y]\) 範圍內的所有元素更新為 \(z\)(即:\(a_x, a_{x+1}, \ldots, a_y\) 的值都將變為 \(z\));2 x y
:查詢區間 \([x,y]\) 範圍內所有元素的最大值。
對於 \(100\%\) 的資料,\(1 \le n,m \le 2 \times 10^5, op \in [1,2],1 \le x \le y \le n, 1 \le z,a_i \le 10^9\)
解題思路:
tag[i]
維護分塊 \(i\) 在整體更新的情況下的數值;sum[i]
維護分塊 \(i\) 在任意時刻的最大值。
示例程式:
#include <bits/stdc++.h> using namespace std; const int maxn = 200020; int n, blo, m, a[maxn], bl[maxn], tag[505], mx[505], op, x, y, z; // blo=sqrt(n)表示每一個分塊的大小 block分塊 // bl[i] 表示第i個點所屬的分塊編號 // 區間更新[l,r]全部更新為z // tag[x]表示第x個分塊在全部一樣(整體更新)的情況下的數值 // mx[x]表示第x個分塊的最大值 // 將tag[x]的值全部更新到屬於第x個分塊的所有元素 void recover(int x) { // [(x-1)*blo+1, min(x*blo, n)] if (tag[x]) { for (int i = (x-1)*blo+1; i <= min(x*blo, n); i ++) a[i] = tag[x]; mx[x] = tag[x]; // 何時何地mx[x]維護的都是區間的最大值 tag[x] = 0; } } // (重新)計算mx[x]的值 void calmx(int x) { mx[x] = 0; for (int i = (x-1)*blo+1; i <= min(x*blo, n); i ++) mx[x] = max(mx[x], a[i]); } void update(int l, int r, int z) { // 1. 處理a[l]所在的分塊(單獨處理) recover(bl[l]); for (int i = l; i <= min(bl[l]*blo, r); i ++) a[i] = z; calmx(bl[l]); // 2. 處理a[r]所在的分塊(單獨處理) if (bl[l] != bl[r]) { recover(bl[r]); for (int i = (bl[r]-1)*blo+1; i <= r; i ++) a[i] = z; calmx(bl[r]); } // 3. 處理 bl[l]+1 到 bl[r]-1 這些中間的完整的分塊 for (int i = bl[l]+1; i < bl[r]; i ++) mx[i] = tag[i] = z; } // 查詢區間[l,r]的最大值 int query(int l, int r) { int res = 0; // 1. 處理a[l]所在的分塊(單獨處理) recover(bl[l]); for (int i = l; i <= min(bl[l]*blo, r); i ++) res = max(res, a[i]); // 2. 處理a[r]所在的分塊(單獨處理) if (bl[l] != bl[r]) { recover(bl[r]); for (int i = (bl[r]-1)*blo+1; i <= r; i ++) res = max(res, a[i]); } // 3. 處理 bl[l]+1 到 bl[r]-1 這些中間的完整的分塊 for (int i = bl[l]+1; i < bl[r]; i ++) res = max(res, mx[i]); return res; } int main() { scanf("%d%d", &n, &m); blo = sqrt(n); for (int i = 1; i <= n; i ++) { scanf("%d", a+i); bl[i] = (i - 1) / blo + 1; mx[bl[i]] = max(mx[bl[i]], a[i]); } while (m --) { scanf("%d%d%d", &op, &x, &y); if (op == 1) { // 區間[x,y]全部更新為z scanf("%d", &z); update(x, y, z); } else { // 查詢區間[x,y]的最大值 printf("%d\n", query(x, y)); } } return 0; }