打打打打打字机|

realFish

园龄:3年2个月粉丝:3关注:0

洛谷P2839 middle 题解

题面

传送门
给定一个长度为 n 的序列 s 以及 Q 个询问,每个询问为:求 s 的左端点在 [a,b],右端点在 [c,d] 的子区间中,最大的中位数。
1n200001Q25000。保证 a<b<c<d。强制在线。

题解

很好的主席树题目,建模巧妙不套路,真正起到了数据结构维护信息的作用。
关于中位数,有一种较为套路的方法。选一个数,将大于此数的数变为 1,小于此数的数变为 1,相加。若结果非负,则此数大于等于中位数。此题中可以以此二分答案,根据是否存在子区间使和大于等于 0 判断 l,r 的移动。
发现 [b+1,c1] 必须取。然后剩余部分用一个小贪心转化为前/后缀和,则 check(x) 函数可以写成:将大于等于 x 的数变为1,否则变为-1,求 [b+1,c1] 的和 + [a,b] 的最大后缀和 + [c,d] 的最大前缀和是否非负。
区间的最大前后缀容易想到线段树。但如上方法要对所有 x 都开一棵线段树,显然不可行。
但又注意到,x1 时,线段树上仅需单点修改(其实并不完全是单点修改,但离散化后 x1n 仅会单点修改 n 次,均摊到每次增加可看做单点修改)。于是想到主席树。
至此,此题的思路已经很清晰了。先离散化,再对每个值开一棵线段树维护原序列区间,且要用主席树。之后就是 上述check 以及线段树常规操作了。时间复杂度 O(Nlog2N),空间复杂度 O(NlogN)

Code
此代码在洛谷上奇怪地错误了。后7个点MLE,唯一可能导致炸空间的只有vector,但其空间仅为 O(N)……
BZOJ可以AC。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 2e4 + 5, M = 8e5 + 5;
int n, a[N], mp[N], m, idx, root[N], q, s[4];
struct Node {int lc, rc, sum, ls, rs;} t[M];
vector<int> c[N];
int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}
    return x * f;
}
void Build(int l, int r, int p) {
    t[p].sum = t[p].ls = t[p].rs = r - l + 1;
    if (l == r) return ;
    int mid = l + r >> 1;
    Build(l, mid, t[p].lc = ++idx); Build(mid + 1, r, t[p].rc = ++idx);
}
void pushup(int p) {
    Node &u = t[p], l = t[t[p].lc], r = t[t[p].rc];
    u.sum = l.sum + r.sum;
    u.ls = max(l.ls, l.sum + r.ls);
    u.rs = max(r.rs, r.sum + l.rs);
}
void Insert(int l, int r, int x, int ex, int p) {
    t[p] = t[ex];
    if (l == r) {
        t[p].sum = t[p].ls = t[p].rs = -1; return ;
    }
    int mid = l + r >> 1, f1 = 0, f2 = 0;
    for (int i = 0; i < c[x].size(); i++)
        if (l <= c[x][i] && c[x][i] <= mid) f1 |= 1;
        else if (mid + 1 <= c[x][i] && c[x][i] <= r) f2 |= 1;
    if (f1) Insert(l, mid, x, t[ex].lc, t[p].lc = ++idx);
    if (f2) Insert(mid + 1, r, x, t[ex].rc, t[p].rc = ++idx);
    pushup(p);
}
int Query(int l, int r, int L, int R, int k, int p) {
    if (L <= l && r <= R) {
        if (k == 1) return t[p].sum;
        else if (k == 2) return t[p].rs;
        return t[p].ls;
    }
    int mid = l + r >> 1, f = (L <= mid) + 2 * (R > mid);
    if (k == 1) {
        if (f == 1) return Query(l, mid, L, R, 1, t[p].lc);
        else if (f == 2) return Query(mid + 1, r, L, R, 1, t[p].rc);
        return Query(l, mid, L, R, 1, t[p].lc) + Query(mid + 1, r, L, R, 1, t[p].rc);
    }
    if (f == 1) return Query(l, mid, L, R, k, t[p].lc);
    else if (f == 2) return Query(mid + 1, r, L, R, k, t[p].rc);
    else {
        if (k == 2) return max(Query(mid + 1, r, L, R, 2, t[p].rc), Query(l, mid, L, R, 2, t[p].lc) + Query(mid + 1, r, L, R, 1, t[p].rc));
        return max(Query(l, mid, L, R, 3, t[p].lc), Query(mid + 1, r, L, R, 3, t[p].rc) + Query(l, mid, L, R, 1, t[p].lc));
    }
}
bool check(int x) {
    int res = 0;
    if (s[1] < s[2] - 1) res += Query(1, m, s[1] + 1, s[2] - 1, 1, root[x]);
    res += Query(1, m, s[0], s[1], 2, root[x]) + Query(1, m, s[2], s[3], 3, root[x]);
    return res >= 0;
}
int main() {
    int ans = 0;
    n = read();
    for (int i = 1; i <= n; i++) mp[i] = a[i] = read();
    sort(mp + 1, mp + n + 1);
    m = unique(mp + 1, mp + n + 1) - (mp + 1);
    for (int i = 1; i <= n; i++) c[lower_bound(mp + 1, mp + m + 1, a[i]) - mp].push_back(i);
    Build(1, m, root[1] = ++idx);
    for (int i = 2; i <= m; i++) Insert(1, m, i - 1, root[i - 1], root[i] = ++idx);
    q = read();
    while (q--) {
        for (int i = 0; i < 4; i++) s[i] = (read() + ans) % n + 1;
        sort(s, s + 4);
        int l = 1, r = m, mid;
        while (l < r) {
            mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        printf("%d\n", ans = mp[l]);
    }
    return 0;
}

本文作者:realFish

本文链接:https://www.cnblogs.com/fish07/p/16208582.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   realFish  阅读(32)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起