CF EDU 102 D - Program
阿新 • • 發佈:2022-05-29
D - Program
st表 / 線段樹
- 若查詢去掉 \([l,r]\) 操作後,整個操作過程中出現的值有哪些,由於每次操作值都是 +1 或 -1,因此是連續的,只要求出整個操作過程中出現的最大值和最小值即可
- 求出字首和, 因為 l 可能為 1,r 可能為 n,所以令 \(s[0]=0,\;s[n+1]=s[n]\)
- 若去掉了 \([l,r]\) 的操作,則 \([0,l-1]\) 中的最大值可能是整個操作的最大值,\([r+1,n+1]\) 的最大值 - \((s[r]-s[l-1])\) 也可能是最大值, 取兩者的最大值,可用 st 表 或線段樹維護區間最值 (注意線段樹不要返回 pair 型別來同時返回最大值,最小值,常數太大會 TLE)
- 最小值同理
#include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; typedef long long ll; const int N = 2e5 + 10, M = 18; int f[N][M], g[N][M], s[N]; int n, m; string str; void init() { for (int j = 0; j < M; j++) for (int i = 0; i + (1 << j) - 1 <= n + 1; i++) if (!j) f[i][j] = s[i]; else f[i][j] = max(f[i][j-1], f[i + (1 << j-1)][j-1]); for (int j = 0; j < M; j++) for (int i = 0; i + (1 << j) - 1 <= n + 1; i++) if (!j) g[i][j] = s[i]; else g[i][j] = min(g[i][j-1], g[i + (1 << j-1)][j-1]); } int query_max(int l, int r) { int len = r - l + 1; int k = log(len) / log(2); return max(f[l][k], f[r - (1<<k) + 1][k]); } int query_min(int l, int r) { int len = r - l + 1; int k = log(len) / log(2); return min(g[l][k], g[r - (1<<k) + 1][k]); } int main() { int T; cin >> T; while(T--) { scanf("%d%d", &n, &m); cin >> str; str = " " + str; for (int i = 1; i <= n; i++) s[i] = s[i-1] + (str[i] == '+' ? 1 : -1); s[n + 1] = s[n]; init(); while(m--) { int l, r; scanf("%d%d", &l, &r); int sub = s[r] - s[l-1]; int l1 = query_min(0, l - 1), r1 = query_max(0, l - 1); int l2 = query_min(r + 1, n + 1) - sub, r2 = query_max(r + 1, n + 1) - sub; int ans = 0; if (max(l1, l2) > min(r1, r2)) ans = r1 - l1 + 1 + r2 - l2 + 1; else ans = max(r1, r2) - min(l1, l2) + 1; printf("%d\n", ans); } } return 0; }
#include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; typedef long long ll; typedef pair<int, int> PII; const int N = 2e5 + 10; const int INF = 1e9; int n, m; string str; int s[N]; struct Node { int l, r; int mx, mn; }tr[N * 4]; void pushup(int u) { tr[u].mn = min(tr[u << 1].mn, tr[u << 1 | 1].mn); tr[u].mx = max(tr[u << 1].mx, tr[u << 1 | 1].mx); } void build(int u, int l, int r) { if (l == r) { tr[u] = {l, r, s[l], s[l]}; return; } tr[u] = {l, r}; int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); pushup(u); } int query_max(int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r) return tr[u].mx; int mid = tr[u].l + tr[u].r >> 1; int maxn = -INF; if (l <= mid) maxn = query_max(u << 1, l, r); if (r > mid) maxn = max(maxn, query_max(u << 1 | 1, l, r)); return maxn; } int query_min(int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r) return tr[u].mn; int mid = tr[u].l + tr[u].r >> 1; int minn = INF; if (l <= mid) minn = query_min(u << 1, l, r); if (r > mid) minn = min(minn, query_min(u << 1 | 1, l, r)); return minn; } int main() { int T; cin >> T; while(T--) { scanf("%d%d", &n, &m); cin >> str; str = " " + str; for (int i = 1; i <= n; i++) s[i] = s[i-1] + (str[i] == '+' ? 1 : -1); s[n + 1] = s[n]; build(1, 0, n + 1); while(m--) { int l, r; scanf("%d%d", &l, &r); int sub = s[r] - s[l-1]; int l1 = query_min(1, 0, l - 1), r1 = query_max(1, 0, l - 1); int l2 = query_min(1, r + 1, n + 1) - sub, r2 = query_max(1, r + 1, n + 1) - sub; int ans = 0; if (max(l1, l2) > min(r1, r2)) ans = r1 - l1 + 1 + r2 - l2 + 1; else ans = max(r1, r2) - min(l1, l2) + 1; printf("%d\n", ans); } } return 0; }