【Luogu P8251】[NOI Online 2022 提高組] 丹釣戰
阿新 • • 發佈:2022-04-10
連結
題目大意
有 \(n\) 個二元組 \((a_i, b_i)\),編號為 \(1\) 到 \(n\)。
有一個初始為空的棧 \(S\),向其中加入元素 \((a_i, b_i)\) 時,先不斷彈出棧頂元素直至棧空或棧頂元素 \((a_j,b_j)\) 滿足 \(a_i \neq a_j\) 且 \(b_i < b_j\),然後再將其加入棧中。
如果一個二元組入棧後棧內只有這一個元素,則稱該二元組是“成功的”。
有 \(q\) 個詢問 \([l_i, r_i]\),表示若將編號在 \([l_i, r_i]\) 中的二元組按編號從小到大依次入棧,會有多少個二元組是“成功的”。
思路
考慮到時間範圍很緊,應該是離線做法。因為是棧,所以想到用 \(p_i\) 先把 \([1,n]\) 每個二元組在棧的位置預處理出來,然後對於子區間 \([l,r]\) 求出有多少個二元組的位置小於等於第 \(l\) 個二元組位置即可。但是若有 \(l+1\) 個二元組比第 \(l\) 個的位置前的多,那麼 \(l+2\) 雖然不是“成功的”,也會誤判。因此考慮並不是預處理位置,而是預處理二元組在棧中的前一個是誰。
然後對於區間求小於等於 \(k\),考慮用主席樹維護。注意:主席樹維護 \(p_i\),要加 1,否則“成功的”二元組的 \(p\) 值為 0,主席樹會出錯。
程式碼:
#include <cmath> #include <queue> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define stoorz_and_QuantAsk using #define AK namespace #define IOI_and_Jayun_is_stupid std #define ll long long stoorz_and_QuantAsk AK IOI_and_Jayun_is_stupid; const int N = 5e5 + 10; inline ll Read() { ll x = 0, f = 1; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') f = -f, c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * f; } int n, q; int a[N], b[N], st[N], top, p[N]; vector <int> v; bool cmp (int mid, int val) { return b[mid] > val; } int root[N]; struct Seg { int lt[N<<5], rt[N<<5], cnt; int sum[N<<5]; void build(int &x, int l, int r) { x = ++cnt; if(l == r) return; int mid = (l + r) >> 1; build(lt[x], l, mid); build(rt[x], mid + 1, r); } int change(int x, int l, int r, int p) { int Newx = ++cnt; lt[Newx] = lt[x], rt[Newx] = rt[x], sum[Newx] = sum[x]; if (l == r) {sum[Newx]++; return Newx;} int mid = (l + r) >> 1; if(p <= mid) lt[Newx] = change(lt[Newx], l, mid, p); else rt[Newx] = change (rt[Newx], mid + 1, r, p); sum[Newx] = sum[lt[Newx]] + sum[rt[Newx]]; return Newx; } int query (int L, int R, int l, int r, int x, int y) { if (x <= l && r <= y) return sum[R] - sum[L]; int ans = 0, mid = (l + r) >> 1; if(x <= mid) ans += query (lt[L], lt[R], l, mid, x, y); if(y > mid) ans += query (rt[L], rt[R], mid + 1, r, x, y); return ans; } }sgt; int main() { freopen("stack.in", "r", stdin); freopen("stack.out", "w", stdout); n = Read(), q = Read(); for (int i = 1; i <= n; i++) a[i] = Read(); for (int i = 1; i <= n; i++) b[i] = Read(); for (int i = 1; i <= n; i++) { if (top == 0) { p[i] = st[top++]; st[top] = i; continue; } top = lower_bound(st + 1, st + 1 + top, b[i], cmp) - st - 1; if (a[st[top]] == a[i]) top--; p[i] = st[top++]; st[top] = i; } sgt.build(root[0], 1, n); for (int i = 1; i <= n; i++) root[i] = sgt.change(root[i - 1], 1, n, p[i]); for (int i = 1; i <= q; i++) { int l = Read(), r = Read(); printf ("%d\n", sgt.query(root[l - 1], root[r], 1, n, 1, p[l])); } return 0; }