先二分答案,转换为判定性问题:
询问mm次区间排序之后,位置上的数是否≥mid≥mid。
然后构建0101序列,对于第ii个位置,如果原序列的第个数≥mid≥mid,则0101序列的第ii个数为,否则为00。
这时候,区间升序排序就相当于把一个区间内的全部放到左边,11全部放到右边,区间降序排序相当于把一个区间内的全部放到右边,11全部放到左边。
因此,需要写一个支持区间赋值和求区间和的线段树。
所有操作都进行完后,如果序列的qq位置上的数为,则原序列mm次区间排序之后位置上的数≥mid≥mid。
复杂度O(nlog2n)O(nlog2n)。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define p2 p << 1
#define p3 p << 1 | 1
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5, M = 4e5 + 5;
int n, m, a[N], op[N], l[N], r[N], q, sum[M], tag[M];
void build(int t, int l, int r, int p) {
if (l == r) return (void) (sum[p] = a[l] >= t, tag[p] = -1);
int mid = l + r >> 1; build(t, l, mid, p2); build(t, mid + 1, r, p3);
sum[p] = sum[p2] + sum[p3]; tag[p] = -1;
}
void down(int p) {
if (tag[p] != -1) tag[p2] = tag[p], tag[p3] = tag[p], tag[p] = -1;
}
void upt(int l, int r, int p) {
int mid = l + r >> 1, ls = sum[p2], rs = sum[p3];
if (tag[p2] != -1) ls = (mid - l + 1) * tag[p2];
if (tag[p3] != -1) rs = (r - mid) * tag[p3]; sum[p] = ls + rs;
}
void change(int l, int r, int s, int e, int v, int p) {
if (l == s && r == e) return (void) (tag[p] = v);
int mid = l + r >> 1; down(p);
if (e <= mid) change(l, mid, s, e, v, p2);
else if (s >= mid + 1) change(mid + 1, r, s, e, v, p3);
else change(l, mid, s, mid, v, p2), change(mid + 1, r, mid + 1, e, v, p3);
upt(l, r, p);
}
int ask(int l, int r, int s, int e, int p) {
if (l == s && r == e) return tag[p] == -1 ? sum[p] : tag[p] * (r - l + 1);
int mid = l + r >> 1; down(p); int res;
if (e <= mid) res = ask(l, mid, s, e, p2);
else if (s >= mid + 1) res = ask(mid + 1, r, s, e, p3);
else res = ask(l, mid, s, mid, p2) + ask(mid + 1, r, mid + 1, e, p3);
return upt(l, r, p), res;
}
bool check(int t) {
int i; build(t, 1, n, 1); for (i = 1; i <= m; i++) {
int tmp = ask(1, n, l[i], r[i], 1);
if (!tmp || tmp == r[i] - l[i] + 1) continue;
if (op[i]) change(1, n, l[i], l[i] + tmp - 1, 1, 1),
change(1, n, l[i] + tmp, r[i], 0, 1);
else change(1, n, r[i] - tmp + 1, r[i], 1, 1),
change(1, n, l[i], r[i] - tmp, 0, 1);
}
return ask(1, n, q, q, 1) == 1;
}
int main() {
int i; n = read(); m = read(); for (i = 1; i <= n; i++) a[i] = read();
for (i = 1; i <= m; i++) op[i] = read(), l[i] = read(), r[i] = read();
q = read(); int l = 1, r = n; while (l <= r) {
int mid = l + r >> 1; check(mid) ? l = mid + 1 : r = mid - 1;
}
cout << r << endl;
return 0;
}