[HEOI2016/TJOI2016]排序
Description
Solution
这里有一个神奇的操作:01排序。如果这个序列只有0和1,那么可以查一个区间内的1的数量,然后把区间中一侧改成1,另一侧改成0就行,可以用线段树排序。
又因为询问只有一个,我们可以二分答案,然后把大于等于答案的数变成1,小于答案的数变成0。01排序后检查q上是不是1就行了。
Code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
typedef long long ll;
const int N = 4 * 100000 + 10;
int tag[N], val[N], mid, a[N], n, m, q;
int sl[N], sr[N], st[N];
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
void pd(int o, int l, int r) {
int mid = (l + r) >> 1;
if (tag[o] != -1) {
tag[o << 1] = tag[o];
tag[o << 1 | 1] = tag[o];
val[o << 1] = (mid - l + 1) * tag[o];
val[o << 1 | 1] = (r - mid) * tag[o];
tag[o] = -1;
}
}
void dfs(int o, int l, int r) {
if (l == r) {
printf("%d %d\n", l, val[o]);
return;
}
pd(o, l, r);
int mid = (l + r) >> 1;
dfs(lson);
dfs(rson);
}
void upd(int o) { val[o] = val[o << 1] + val[o << 1 | 1]; }
void build(int o, int l, int r) {
tag[o] = -1;
if (l == r) {
val[o] = (a[l] >= mid);
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
upd(o);
}
void modi(int o, int l, int r, int ql, int qr, int v) {
if (ql <= l && r <= qr) {
tag[o] = v;
val[o] = v * (r - l + 1);
return;
}
pd(o, l, r);
int mid = (l + r) >> 1;
if (ql <= mid) modi(lson, ql, qr, v);
if (qr > mid) modi(rson, ql, qr, v);
upd(o);
}
int query(int o, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return val[o];
}
pd(o, l, r);
int ans = 0, mid = (l + r) >> 1;
if (ql <= mid) ans += query(lson, ql, qr);
if (qr > mid) ans += query(rson, ql, qr);
return ans;
}
void sort(int l, int r, int tag) {
int x = query(1, 1, n, l, r);
if (tag) {
if (l <= l + x - 1) modi(1, 1, n, l, l + x - 1, 1);
if (l + x <= r) modi(1, 1, n, l + x, r, 0);
} else {
if (r - x + 1 <= r) modi(1, 1, n, r - x + 1, r, 1);
if (l <= r - x) modi(1, 1, n, l, r - x, 0);
}
}
bool check(int x) {
mid = x;
build(1, 1, n);
for (int i = 1; i <= m; ++i) {
sort(sl[i], sr[i], st[i]);
}
return query(1, 1, n, q, q);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= m; ++i) scanf("%d%d%d", &st[i], &sl[i], &sr[i]);
scanf("%d", &q);
int l = 1, r = n, ans = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) {
l = mid + 1;
ans = mid;
} else {
r = mid - 1;
}
}
printf("%d\n", ans);
return 0;
}