【題解】P2839 [國家集訓隊]middle
阿新 • • 發佈:2022-01-05
描述:
一個長度為 \(n\) 的序列 \(a\),設其排過序之後為 \(b\),其中位數定義為 \(b_{n/2}\),其中 \(a,b\) 從 \(0\) 開始標號,除法取下整。
給你一個長度為 \(n\) 的序列 \(s\)。
回答 \(Q\) 個這樣的詢問:\(s\) 的左端點在 \([a,b]\) 之間,右端點在 \([c,d]\) 之間的子區間中,最大的中位數。
\(n \leq 20000\),\(Q \leq 25000\)。強制線上。
思路:
看到求 最大 的中位數,想到二分。
二分 \(mid\) ,將大於等於 \(mid\) 的數的值設為 \(1\) ,小於 \(mid\) 的數的值設為 \(0\)
那麼當區間和為 \(0\) 時,\(mid\) 為區間的中位數。
二分的時候,區間和 \(\ge 0\) ,那麼中位數應該比 \(mid\) 大,反之,則更小。
那麼我們應該要區間儘量大。
考慮暴力,對於每個二分的值,預處理出它對應的序列的線段樹。
當我們發現建立線段樹的時間複雜度或空間複雜度過高時,考慮利用原有資訊,也就是主席樹。(如:對每個量建立一顆線段樹)
那麼可以將值排序,發現每次改動只會將一個位置的 \(1\) 變為 \(-1\) 。
時間複雜度 \(O(n\log^2 n)\)
程式碼:
Undersea Palace#include <bits/stdc++.h> #define LL long long #define ULL unsigned long long #define DB double #define PR pair <int, int> #define MK make_pair #define pb push_back #define fi first #define se second #define RI register int #define Low(x) (x & (-x)) using namespace std; const int kN = 3e4 + 5; int n, A[kN], rt[kN], cnt, Q; PR B[kN]; struct Node { int siz, lm, rm; }; struct Smt { Node d[kN * 40]; int ls[kN * 40], rs[kN * 40]; #define ls(p) ls[p] #define rs(p) rs[p] Node Merge(Node x, Node y) { Node res; res.siz = x.siz + y.siz; res.lm = max(x.lm, x.siz + y.lm); res.rm = max(y.rm, y.siz + x.rm); return res; } void Build(int l, int r, int &p) { p = ++cnt; if (l == r) {d[p] = {1, 1, 1}; return;} int mid = (l + r) >> 1; Build(l, mid, ls(p)), Build(mid + 1, r, rs(p)); d[p] = Merge(d[ls(p)], d[rs(p)]); } void Modify(int l, int r, int pos, int k, int &p1, int &p2) { p2 = ++cnt; ls(p2) = ls(p1), rs(p2) = rs(p1); d[p2] = d[p1]; if (l == r) {d[p2].siz += k, d[p2].lm = d[p2].rm = d[p2].siz; return;} int mid = (l + r) >> 1; if (pos <= mid) Modify(l, mid, pos, k, ls(p1), ls(p2)); else Modify(mid + 1, r, pos, k, rs(p1), rs(p2)); d[p2] = Merge(d[ls(p2)], d[rs(p2)]); } Node Query(int l, int r, int L, int R, int p) { if (L > R) return (Node) {0, 0, 0}; if (l >= L && r <= R) return d[p]; int mid = (l + r) >> 1; if (L <= mid && R > mid) return Merge(Query(l, mid, L, R, ls(p)), Query(mid + 1, r, L, R, rs(p))); if (L <= mid) return Query(l, mid, L, R, ls(p)); return Query(mid + 1, r, L, R, rs(p)); } } T; signed main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &A[i]), B[i] = MK(A[i], i); sort(B + 1, B + 1 + n); T.Build(1, n, rt[1]); for (int i = 2; i <= n; ++i) { T.Modify(1, n, B[i - 1].se, -2, rt[i - 1], rt[i]); } int las = 0; scanf("%d", &Q); while (Q--) { int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d); int q[4] = {(a + las) % n, (b + las) % n, (c + las) % n, (d + las) % n}; sort(q, q + 4); a = q[0] + 1, b = q[1] + 1, c = q[2] + 1, d = q[3] + 1; // cout << a << ' ' << b << ' ' << c << ' ' << d << endl; int l = 1, r = n, ans = 0; while (l <= r) { int mid = (l + r) >> 1; Node x = T.Query(1, n, a, b, rt[mid]), y = T.Query(1, n, b + 1, c - 1, rt[mid]), z = T.Query(1, n, c, d, rt[mid]); int res = x.rm + y.siz + z.lm; if (res >= 0) ans = mid, l = mid + 1; else r = mid - 1; } printf("%d\n", las = B[ans].fi); } return 0; }