【LG2839】[国家集训队]middle
【LG2839】[国家集训队]middle
题面
题解
按照求中位数的套路,我们二分答案\(mid\),将大于等于\(mid\)的数设为\(1\),否则为\(-1\)。
若一个区间和大于等于\(0\),则答案可以更大,反之亦然。
对于这个题,我们只要维护出\([b+1,c-1]\)之间二分答案后的和,\([a,b]\)的最大右段和,\([c,d]\)的最大左段和,判断这三项加起来是否大于零即可。
我们维护这三项和的话,按照权值为前缀,建主席树就行了。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
const int MAX_N = 2e4 + 5;
struct Info {
int lmax, rmax, sum;
Info () {lmax = rmax = -1, sum = 0; }
Info (int lmax, int rmax, int sum) : lmax(lmax), rmax(rmax), sum(sum) { }
} ;
Info operator + (Info l, Info r) {
Info res;
res.lmax = max(l.lmax, l.sum + r.lmax);
res.rmax = max(r.rmax, r.sum + l.rmax);
res.sum = l.sum + r.sum;
return res;
}
struct Node { int ls, rs; Info v; } t[MAX_N * 20];
int rt[MAX_N], tot = 0;
void build(int &o, int l, int r) {
o = ++tot;
t[o].v = (Info){r - l + 1, r - l + 1, r - l + 1};
if (l == r) return ;
int mid = (l + r) >> 1;
build(t[o].ls, l, mid);
build(t[o].rs, mid + 1, r);
}
void insert(int &o, int p, int l, int r, int pos) {
o = ++tot, t[o] = t[p];
if (l == r) return (void)(t[o].v = (Info){-1, -1, -1});
int mid = (l + r) >> 1;
if (pos <= mid) insert(t[o].ls, t[p].ls, l, mid, pos);
else insert(t[o].rs, t[p].rs, mid + 1, r, pos);
t[o].v = t[t[o].ls].v + t[t[o].rs].v;
}
Info query(int o, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return t[o].v;
int mid = (l + r) >> 1; Info res;
if (ql <= mid) res = res + query(t[o].ls, l, mid, ql, qr);
if (qr > mid) res = res + query(t[o].rs, mid + 1, r, ql, qr);
return res;
}
int N, id[MAX_N], a[MAX_N], q[5];
bool check(int mid) {
int val = 0;
if (q[1] + 1 <= q[2] - 1) val += query(rt[mid], 1, N, q[1] + 1, q[2] - 1).sum;
val += query(rt[mid], 1, N, q[0], q[1]).rmax;
val += query(rt[mid], 1, N, q[2], q[3]).lmax;
return val >= 0;
}
bool cmp(const int &x, const int &y) { return a[x] < a[y]; }
int main() {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
N = gi(); build(rt[1], 1, N);
for (int i = 1; i <= N; i++) a[i] = gi(), id[i] = i;
sort(&id[1], &id[N + 1], cmp);
for (int i = 2; i <= N; i++) insert(rt[i], rt[i - 1], 1, N, id[i - 1]);
for (int Q = gi(), ans = 0; Q--; ) {
for (int i = 0; i < 4; i++) q[i] = (gi() + ans) % N + 1;
sort(&q[0], &q[4]);
int l = 1, r = N;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) ans = a[id[mid]], l = mid + 1;
else r = mid - 1;
}
printf("%d\n", ans);
}
return 0;
}