[国家集训队]middle - Luogu P2839

Luogu P2839 - 传送门

Middle

题目描述 :

一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。

给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。

其中a<b<c<d。
位置也从0开始标号。
使用一些方式强制你在线。

输入格式 :

第一行序列长度n。
接下来n行按顺序给出a中的数。

接下来一行Q。
然后Q行每行a,b,c,d,我们令上个询问的答案是x(如果这是第一个询问则x=0)。

令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。

将q从小到大排序之后,令真正的要询问的a=q[0],b=q[1],c=q[2],d=q[3]。

输出格式 :

Q行依次给出询问的答案。

Solution :

  1. 首先对于中位数,对于一个固定的区间,二分一个 x 将区间里大于等于 x 的数赋为 1,小于 x的数赋为 -1,若区间和大于等于 0 ,则该 x <= 最大的中位数
  2. 对于题目给出的区间,左右端点不固定,对于 b+1 到 c-1间的值是一定要算的,而 a 到 b 的可以记录一个最大的后缀,对 c 到 d 同理记录一个最大的前缀,然后判断这三者值的和是否 >=0 即可

所以可以用二分 + 主席树 然而我不会,或者分块做,对于每个块只需要记录块内存在的值对应的区间和、前缀、后缀最大值,然后对于不存在的值,用比它大的值暴力更新即可,因为该值在块内不存在,所以它的区间和、前缀后缀都与比它大的第一个存在的值相等。

Code :

#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 7, B = 155, inf = 1e5;
int n, m, len, nn;
int l1, l2, r1, r2;
int a[N], h[N], blo[N];
int Lx[B][N], Rx[B][N], Sx[B][N];
template<class T> inline void read(T &x) {
    bool f = false; x = 0;
    char ch = getchar();
    while (ch<'0' || ch>'9') {if (ch == '-') f = true; ch = getchar();}
    while (ch>='0' && ch<='9') x = x * 10 + ch - '0', ch = getchar();
    if (f) x = -x;
}
inline void Init() {
    for (int i = 0; i <= B - 5; i++) {
        for (int j = 0; j <= len + 5; j++) {
            Lx[i][j] = Rx[i][j] = Sx[i][j] = -inf;
        }
    }
    for (int blk = 1; blk <= (n - 1) / nn + 1; blk ++) {
        int L = (blk - 1) * nn + 1, R = min(blk * nn, n);
        for (int i = L; i <= R; i++) {
            int nw = a[i], sum = 0;
            for (int j = L; j <= R; j++) {
                sum += a[j] >= nw ? 1 : -1;
            }
            Sx[blk][nw] = sum;
            sum = 0;
            for (int j = L; j <= R; j++) {
                sum += a[j] >= nw ? 1 : -1;
                Lx[blk][nw] = max(Lx[blk][nw], sum);
            }
            sum = 0;
            for (int j = R; j >= L; j--) {
                sum += a[j] >= nw ? 1 : -1;
                Rx[blk][nw] = max(Rx[blk][nw], sum);
            }
        }
        // Sx[blk][len + 1] = Lx[blk][len + 1] = Rx[blk][len + 1] = -inf;
        for (int i = len; i >= 1; i--) {
            Sx[blk][i] = max(Sx[blk][i], Sx[blk][i + 1]);
            Lx[blk][i] = max(Lx[blk][i], Lx[blk][i + 1]);
            Rx[blk][i] = max(Rx[blk][i], Rx[blk][i + 1]);
        }
    }
}
inline int getSum(int u, int v, int w) {
    if (u > v) return 0;
    int res = 0;
    if (blo[u] == blo[v]) {
        for (int i = u; i <= v; i++)
            res += a[i] >= w ? 1 : -1;
        return res;
    }
    for (int i = u; i <= nn * blo[u]; i++) 
        res += a[i] >= w ? 1 : -1;
    for (int i = blo[u] + 1; i <= blo[v] - 1; i++) 
        res += Sx[i][w];
    for (int i = nn * (blo[v] - 1) + 1; i <= v; i++) 
        res += a[i] >= w ? 1 : -1;
    return res;
}
inline int getLx(int u, int v, int w) {
    int mx = -inf, sum = 0;
    if (blo[u] == blo[v]) {
        for (int i = u; i <= v; i++) {
            sum += a[i] >= w ? 1 : -1;
            mx = max(mx, sum);
        }
        return mx;
    }
    for (int i = u; i <= nn * blo[u]; i++) {
        sum += a[i] >= w ? 1 : -1;
        mx = max(mx, sum);
    }
    for (int i = blo[u] + 1; i <= blo[v] - 1; i++) {
        mx = max(mx, sum + Lx[i][w]);
        sum += Sx[i][w];
    }
    for (int i = nn * (blo[v] - 1) + 1; i <= v; i++) {
        sum += a[i] >= w ? 1 : -1;
        mx = max(mx, sum);
    }
    return mx;
}
inline int getRx(int u, int v, int w) {
    int mx = -inf, sum = 0;
    if (blo[u] == blo[v]) {
        for (int i = v; i >= u; i--) {
            sum += a[i] >= w ? 1 : -1;
            mx = max(mx, sum);
        }
        return mx;
    }
    for (int i = v; i >= nn * (blo[v] - 1) + 1; i--) {
        sum += a[i] >= w ? 1 : -1;
        mx = max(mx, sum);
    }
    for (int i = blo[v] - 1; i >= blo[u] + 1; i--) {
        mx = max(mx, sum + Rx[i][w]);
        sum += Sx[i][w];
    }
    for (int i = nn * blo[u]; i >= u; i--) {
        sum += a[i] >= w ? 1 : -1;
        mx = max(mx, sum);
    }
    return mx;
}
inline bool judge(int k) {
    return getRx(l1, r1, k) + getSum(r1 + 1, l2 - 1, k) + getLx(l2, r2, k) >= 0;
}
int main() {
    read(n);
    nn = sqrt(n);
    for (int i = 1; i <= n; i++) {
        read(a[i]);
        h[i] = a[i];
        blo[i] = (i - 1) / nn + 1;
    }
    sort(h + 1, h + 1 + n);
    len = unique(h + 1, h + 1 + n) - h - 1;
    for (int i = 1; i <= n; i++) {
        a[i] = lower_bound(h + 1, h + 1 + len, a[i]) - h;
    }
    Init(); read(m);
    int prv = 0, q[5];
    for (int i = 1; i <= m; i++) {
        read(l1), read(r1), read(l2), read(r2);
        q[1] = (l1 + prv) % n; q[2] = (r1 + prv) % n;
        q[3] = (l2 + prv) % n; q[4] = (r2 + prv) % n;
        sort(q + 1, q + 1 + 4);
        l1 = q[1] + 1, r1 = q[2] + 1, l2 = q[3] + 1, r2 = q[4] + 1;
        int l = 1, r = len, pos;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (judge(mid)) pos = mid, l = mid + 1;
            else r = mid - 1;
        }
        printf("%d\n", prv = h[pos]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/bryane/p/11708942.html
今日推荐