【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;
}
01-23 07:44