E. Sign on Fence
给定一个长度为nnn的数组aaa,1≤ai≤1091 \leq a_i \leq 10 ^ 91≤ai≤109,有mmm次询问,每次给定l,r,kl, r, kl,r,k,要我们在[l,r][l, r][l,r]区间内找到一个长度为kkk的区间,使得区间最小值最大,输出最大值。
考虑二分答案,如果当前二分的区间是[l,r][l, r][l,r],我们把大于midmidmid的点,在数组中都设置为111,小于等于midmidmid的点,在数组中都设置为000,
考虑用线段树维护一个区间最长连续111的长度,对于每组询问,我们每次查询区间[li,ri][l_i, r_i][li,ri]的最长连续111长度是否大于等于kik_iki即可,
由于单次查询的复杂度是O(nlognlogn)O(n \log n \log n)O(nlognlogn),所以可以考虑整体二分,复杂度同样也是O(nlognlogn)O(n \log n \log n)O(nlognlogn)的,
整体二分的时候我们先递归去处理[l,mid][l, mid][l,mid],这个时候不清空线段树,当我们处理[mid+1,r][mid + 1, r][mid+1,r]的时候,再清空线段树。
#include <bits/stdc++.h>using namespace std;const int N = 2e5 + 10;struct Seg {int l, r, res, len;
}a[N << 2];Seg operator + (Seg a, Seg b) {Seg ans;ans.len = a.len + b.len;ans.l = a.l == a.len ? a.l + b.l : a.l;ans.r = b.r == b.len ? b.r + a.r : b.r;ans.res = max({a.res, b.res, a.r + b.l});return ans;
}void push_up(int rt) {a[rt] = a[rt << 1] + a[rt << 1 | 1];
}void build(int rt, int l, int r) {if (l == r) {a[rt] = {0, 0, 0, 1};return ;}int mid = l + r >> 1;build(rt << 1, l, mid);build(rt << 1 | 1, mid + 1, r);push_up(rt);
}void update(int rt, int l, int r, int x, int v) {if (l == r) {a[rt] = {v, v, v, 1};return ;}int mid = l + r >> 1;if (x <= mid) {update(rt << 1, l, mid, x, v);}else {update(rt << 1 | 1, mid + 1, r, x, v);}push_up(rt);
}Seg query(int rt, int l, int r, int L, int R) {if (l >= L && r <= R) {return a[rt];}int mid = l + r >> 1;if (L <= mid && R > mid) {return query(rt << 1, l, mid, L, R) + query(rt << 1 | 1, mid + 1, r, L, R);}else if (L <= mid) {return query(rt << 1, l, mid, L, R);}else {return query(rt << 1 | 1, mid + 1, r, L, R);}
}struct Res {int l, r, id, k, op;
}q[N << 1], q1[N << 1], q2[N << 1];int b[N], ans[N], n, m, tot;void solve(int l, int r, int L, int R) {if (l > r || L > R) {return ;}if (l == r) {for (int i = L; i <= R; i++) {if (q[i].op) {ans[q[i].id] = b[l];}}return ;}int mid = l + r >> 1, cnt1 = 0, cnt2 = 0;for (int i = L; i <= R; i++) {if (q[i].op) {int cur = query(1, 1, n, q[i].l, q[i].r).res;if (cur >= q[i].k) {q2[++cnt2] = q[i];}else {q1[++cnt1] = q[i];}}else {if (q[i].k > b[mid]) {update(1, 1, n, q[i].id, 1);q2[++cnt2] = q[i];}else {q1[++cnt1] = q[i];}}}for (int i = 1; i <= cnt1; i++) {q[L + i - 1] = q1[i];}for (int i = 1; i <= cnt2; i++) {q[L + cnt1 + i - 1] = q2[i];}solve(l, mid, L, L + cnt1 - 1);for (int i = L; i <= R; i++) {if (!q[i].op && q[i].k > b[mid]) {update(1, 1, n, q[i].id, 0);}}solve(mid + 1, r, L + cnt1, R);
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d", &n);int cnt = 0;for (int i = 1; i <= n; i++) {scanf("%d", &b[i]);q[++cnt] = {0, 0, i, b[i], 0};}scanf("%d", &m);for (int i = 1, l, r, k; i <= m; i++) {scanf("%d %d %d", &l, &r, &k);q[++cnt] = {l, r, i, k, 1};}sort(b + 1, b + 1 + n);tot = unique(b + 1, b + 1 + n) - (b + 1);build(1, 1, n);solve(1, tot, 1, cnt);for (int i = 1; i <= m; i++) {printf("%d\n", ans[i]);}return 0;
}