【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;
}

猜你喜欢

转载自www.cnblogs.com/heyujun/p/11695299.html