【题目链接】
【思路要点】
- 中位数相关,考虑二分答案。
- 我们现在想要检验\(Mid\)是否能够作为中位数出现,令大于等于\(Mid\)的元素为1,其余元素为-1,我们希望求出一个左右端点都在给定范围内的区间,使得区间和最大,若这个区间和非负,那么\(Mid\)能够作为中位数出现,否则不能。
- 这个问题等价于找到在给定范围内的左右端点,使得左端点到1的和最小,右端点到\(N\)的和最小。
- 我们将序列中的所有元素从大到小排序,初始时,令所有元素为-1,按从大到小的顺序依次将-1改写为1。
- 改写一个元素等价于对前/后缀和进行区间加操作,额外维护区间最小值即可回答询问。
- 将上述过程可持久化,即可完成本题。
- 时间复杂度\(O(NLogN+QLog^2N)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 20005; const int MAXP = 3e6 + 5; const int INF = 1e9; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc; int premin, pretag; int sufmin, suftag; } a[MAXP]; int n, size; int build(int l, int r) { int ans = ++size, mid = (l + r) / 2; a[ans].premin = -r; a[ans].sufmin = -(n - l + 1); a[ans].pretag = 0; a[ans].suftag = 0; if (l == r) return ans; a[ans].lc = build(l, mid); a[ans].rc = build(mid + 1, r); return ans; } int init(int x) { n = x; return build(1, n); } void pushdown(int root) { if (a[root].pretag == 0 && a[root].suftag == 0) return; int lc = ++size; a[lc] = a[a[root].lc]; a[lc].pretag += a[root].pretag; a[lc].premin += a[root].pretag; a[lc].suftag += a[root].suftag; a[lc].sufmin += a[root].suftag; a[root].lc = lc; int rc = ++size; a[rc] = a[a[root].rc]; a[rc].pretag += a[root].pretag; a[rc].premin += a[root].pretag; a[rc].suftag += a[root].suftag; a[rc].sufmin += a[root].suftag; a[root].rc = rc; a[root].pretag = a[root].suftag = 0; } void update(int root) { a[root].premin = min(a[a[root].lc].premin, a[a[root].rc].premin); a[root].sufmin = min(a[a[root].lc].sufmin, a[a[root].rc].sufmin); } int preadd(int root, int l, int r, int ql, int qr) { int ans = ++size; a[ans] = a[root]; if (l == ql && r == qr) { a[ans].pretag += 2; a[ans].premin += 2; return ans; } pushdown(root); a[ans] = a[root]; int mid = (l + r) / 2; if (mid >= ql) a[ans].lc = preadd(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) a[ans].rc = preadd(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); update(ans); return ans; } int sufadd(int root, int l, int r, int ql, int qr) { int ans = ++size; a[ans] = a[root]; if (l == ql && r == qr) { a[ans].suftag += 2; a[ans].sufmin += 2; return ans; } pushdown(root); a[ans] = a[root]; int mid = (l + r) / 2; if (mid >= ql) a[ans].lc = sufadd(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) a[ans].rc = sufadd(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); update(ans); return ans; } int extend(int root, int pos) { int ans = preadd(root, 1, n, pos, n); ans = sufadd(ans, 1, n, 1, pos); return ans; } int querysuf(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].sufmin; pushdown(root); int ans = INF, mid = (l + r) / 2; if (mid >= ql) chkmin(ans, querysuf(a[root].lc, l, mid, ql, min(mid, qr))); if (mid + 1 <= qr) chkmin(ans, querysuf(a[root].rc, mid + 1, r, max(mid + 1, ql), qr)); return ans; } int querysuf(int root, int l, int r) { if (l == n) return 0; if (r == n) return min(querysuf(root, 1, n, l + 1, n), 0); else return querysuf(root, 1, n, l + 1, r + 1); } int querypre(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].premin; pushdown(root); int ans = INF, mid = (l + r) / 2; if (mid >= ql) chkmin(ans, querypre(a[root].lc, l, mid, ql, min(mid, qr))); if (mid + 1 <= qr) chkmin(ans, querypre(a[root].rc, mid + 1, r, max(mid + 1, ql), qr)); return ans; } int querypre(int root, int l, int r) { if (r == 1) return 0; if (l == 1) return min(querypre(root, 1, n, 1, r - 1), 0); else return querypre(root, 1, n, l - 1, r - 1); } } ST; struct info {int x, home; } p[MAXN]; int n, q, root[MAXN]; bool cmp(info a, info b) { return a.x > b.x; } int main() { read(n); for (int i = 1; i <= n; i++) { int x; read(x); p[i] = (info) {x, i}; } sort(p + 1, p + n + 1, cmp); root[0] = ST.init(n); for (int i = 1; i <= n; i++) root[i] = ST.extend(root[i - 1], p[i].home); read(q); int lastans = 0; for (int i = 1; i <= q; i++) { int opt[4]; for (int j = 0; j <= 3; j++) read(opt[j]), opt[j] = (opt[j] + lastans) % n + 1; sort(opt, opt + 4); int a = opt[0], b = opt[1]; int c = opt[2], d = opt[3]; int l = 1, r = n; while (l < r) { int mid = (l + r) / 2, tmp = mid - (n - mid); if (tmp - ST.querypre(root[mid], a, b) - ST.querysuf(root[mid], c, d) >= 0) r = mid; else l = mid + 1; } writeln(lastans = p[l].x); } return 0; }