[BZOJ 2653]middle

Description

题库链接

一个长度为 $n$ 的序列 $A$ ,设其排过序之后为 $B$ ,其中位数定义为 $B\left[\left\lfloor\frac{n}{2}\right\rfloor\right]$ ,其中 $A,B$ 从 $0$ 开始标号。给你一个长度为 $n$ 的序列 $S$ 。回答 $Q$ 个这样的询问: $S$ 的左端点在 $[a,b]$ 之间,右端点在 $[c,d]$ 之间的子序列中,最大的中位数。

强制在线。

$1\leq n\leq 20000,1\leq Q\leq 25000$

Solution

二分答案。

对于 $<mid$ 的数变为 $-1$ ,而 $\geq mid$ 的数变为 $1$ 。

那么只要统计 $[a,b]$ 中的最大后缀, $(b,c)$ 总和,及 $[c,d]$ 中的最大前缀。

主席树维护,乱搞一下就好了。

Code

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N = 20000;

int n, Q, mp[N+5], a[N+5], tot, q[5], last_ans;
vector<int>to[N+5];

struct node {
    int lmax, rmax, tol;
    node (int _lmax = 0, int _rmax = 0, int _tol = 0) {lmax = _lmax, rmax = _rmax, tol = _tol; }
    node operator + (const node &b) const {
        node ans;
        ans.tol = tol+b.tol, ans.lmax = max(lmax, tol+b.lmax), ans.rmax = max(b.rmax, b.tol+rmax);
        return ans;
    }
};
struct Segment_tree {
    node sgm[N*50+5]; int ch[N*50+5][2], root[N+5], pos;
    int cpynode(int o) {++pos; sgm[pos] = sgm[o]; ch[pos][0] = ch[o][0], ch[pos][1] = ch[o][1]; return pos; }
    void build(int &o, int l, int r) {
        o = cpynode(o); int mid = (l+r)>>1;
        if (l == r) {sgm[o] = node(1, 1, 1); return; }
        build(ch[o][0], l, mid); build(ch[o][1], mid+1, r);
        sgm[o] = sgm[ch[o][0]]+sgm[ch[o][1]];
    }
    void update(int &o, int l, int r, int loc) {
        o = cpynode(o); int mid = (l+r)>>1;
        if (l == r) {sgm[o] = node(-1, -1, -1); return; }
        if (loc <= mid) update(ch[o][0], l, mid, loc);
        else update(ch[o][1], mid+1, r, loc);
        sgm[o] = sgm[ch[o][0]]+sgm[ch[o][1]];
    }
    node query(int o, int l, int r, int a, int b) {
        if (a <= l && r <= b) return sgm[o]; int mid = (l+r)>>1;
        if (a <= mid && b > mid) return query(ch[o][0], l, mid, a, b)+query(ch[o][1], mid+1, r, a, b);
        if (b <= mid) return query(ch[o][0], l, mid, a, b);
        return query(ch[o][1], mid+1, r, a, b);
    }
}T;
bool check(int x, int a, int b, int c, int d) {
    int val = 0;
    if (b+1 <= c-1) val = T.query(T.root[x], 1, n, b+1, c-1).tol;
    val += T.query(T.root[x], 1, n, a, b).rmax+T.query(T.root[x], 1, n, c, d).lmax;
    return val >= 0;    
}
void work() {
    scanf("%d", &n); tot = n;
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]), mp[i] = a[i];
    sort(mp+1, mp+n+1); tot = unique(mp+1, mp+tot+1)-mp-1;
    for (int i = 1; i <= n; i++) a[i] = lower_bound(mp+1, mp+tot+1, a[i])-mp, to[a[i]].pb(i);
    T.build(T.root[1], 1, n);
    for (int i = 2; i <= tot; i++) {
        T.root[i] = T.root[i-1];
        for (int j = 0, sz = to[i-1].size(); j < sz; j++)
            T.update(T.root[i], 1, n, to[i-1][j]);
    }
    scanf("%d", &Q);
    while (Q--) {
        for (int i = 0; i < 4; i++) scanf("%d", &q[i]), (q[i] += last_ans) %= n, ++q[i];
        sort(q, q+4);
        int L = 1, R = tot;
        while (L <= R) {
            int mid = (L+R)>>1;
            if (check(mid, q[0], q[1], q[2], q[3])) last_ans = mp[mid], L = mid+1;
            else R = mid-1;
        }
        printf("%d\n", last_ans);
    }
}
int main() {work(); return 0; }
posted @ 2018-04-11 20:14  NaVi_Awson  阅读(154)  评论(0编辑  收藏  举报