Codeforces 484 E. Sign on Fence

[传送门]

题意就是给一排围栏,每个围栏都有一个高度,查询区间$\left[l, r\right]$之间长度为$w$的子区间的最小高度的最大值。
首先,这个最大值肯定是这个区间里的围栏的某个高度,如果是一个未出现过的高度,显然能有更高的高度满足条件。
那么就可以考虑在离散化后的高度数组里二分答案,然后check一下这个区间里是否有连续$w$个围栏的高度大于等于这个答案。
因为答案肯定是出现过的高度这个性质,那么可以考虑以高度建一棵可持久化线段树,先将高度数组离散化排好序,第$i$个版本的线段树代表的是下标位置的围栏的高度是否大于等于$h_i$,然后保存区间前缀最长连续1、后缀最长连续1、区间最长连续1。第$i$个版本由第$i-1$个版本再加上几个单点修改得来。
查询就保存区间最长前缀及最长后缀进行合并,合并过程更新一下答案。
说起来容易想起来难。我菜爆了。

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 7;
int n, a[N], h[N], root[N], tol, ans;
vector<int> G[N];

struct Seg {
    struct Tree {
        int lp, rp, len, pre, suf, mx;
    } tree[N * 25];
    inline void pushup(int p) {
        tree[p].pre = tree[tree[p].lp].pre + (tree[tree[p].lp].pre == tree[tree[p].lp].len ? tree[tree[p].rp].pre : 0);
        tree[p].suf = tree[tree[p].rp].suf + (tree[tree[p].rp].suf == tree[tree[p].rp].len ? tree[tree[p].lp].suf : 0);
        tree[p].mx = max(tree[tree[p].lp].suf + tree[tree[p].rp].pre, max(tree[tree[p].lp].mx, tree[tree[p].rp].mx));
    }
    void build(int &p, int l, int r) {
        p = ++tol;
        tree[p].len = tree[p].pre = tree[p].suf = tree[p].mx = r - l + 1;
        if (l == r) return;
        int mid = l + r >> 1;
        build(tree[p].lp, l, mid);
        build(tree[p].rp, mid + 1, r);
    }
    void update(int &p, int q, int l, int r, int pos) {
        tree[p = ++tol] = tree[q];
        if (l == r) {
            tree[p].pre = tree[p].suf = tree[p].mx = 0;
            return;
        }
        int mid = l + r >> 1;
        if (pos <= mid) update(tree[p].lp, tree[q].lp, l, mid, pos);
        else update(tree[p].rp, tree[q].rp, mid + 1, r, pos);
        pushup(p);
    }
    pair<int, int> query(int p, int l, int r, int x, int y) {
        if (x <= l && y >= r) {
            ans = max(ans, tree[p].mx);
            return pair<int, int>(tree[p].pre, tree[p].suf);
        }
        int mid = l + r >> 1;
        pair<int, int> L(0, 0), R(0, 0);
        if (x <= mid) L = query(tree[p].lp, l, mid, x, y);
        if (y > mid) R = query(tree[p].rp, mid + 1, r, x, y);
        ans = max(ans, L.second + R.first); 
        return pair<int, int>(L.first + (L.first == tree[tree[p].lp].len ? R.first : 0),
                              R.second + (R.second == tree[tree[p].rp].len ? L.second : 0));
    }
} seg;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]), h[i] = a[i];
    sort(h + 1, h + 1 + n);
    int cnt = unique(h + 1, h + 1 + n) - h - 1;
    for (int i = 1; i <= n; i++) {
        int pos = lower_bound(h + 1, h + 1 + cnt, a[i]) - h;
        G[pos].push_back(i);
    }
    seg.build(root[1], 1, n);
    for (int i = 2; i <= cnt; i++) {
        root[i] = root[i - 1];
        for (int x: G[i - 1]) {
            seg.update(root[i], root[i], 1, n, x);
        }
    }
    int q;
    scanf("%d", &q);
    while (q--) {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        int res = 0;
        int l = 1, r = cnt;
        while (l <= r) {
            int mid = (l + r + 1) >> 1;
            ans = 0;
            seg.query(root[mid], 1, n, x, y);
            if (ans >= w) l = mid + 1, res = mid;
            else r = mid - 1;
        }
        printf("%d\n", h[res]);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/11673034.html