题意:给出一个排列,每次操作[l,r]区间的数原地升序或者降序,询问最后k下标的数。
二分最后的结果mid,然后把比mid大的换成1,小于等于mid的换成0,那么升序降序相当于求出区间中0的个数然后把前半段和后半段分别用0\1覆盖。这样只需要维护一个区间查询,区间修改的线段树即可。
#include
#include
#include
#include
#include
using namespace std;
#define pl c<<1
#define pr (c<<1)|1
#define lson tree[c].l,tree[c].mid,pl
#define rson tree[c].mid+1,tree[c].r,pr
#define maxn 100005
struct node {
int l, r, mid;
bool zero, one;///全0全1标记
int num;///0个数
}tree[maxn<<3];
int op[maxn][3];
int a[maxn], b[maxn];
int n, m, k;
void build_tree (int l, int r, int c) {
tree[c].l = l, tree[c].r = r, tree[c].mid = (l+r)>>1;
tree[c].zero = tree[c].one = 0;
if (l == r) {
tree[c].num = (b[l] == 0);
return ;
}
build_tree (lson);
build_tree (rson);
tree[c].num = tree[pl].num + tree[pr].num;
}
void push_down (int c) {
if (tree[c].l == tree[c].r) return ;
if (tree[c].zero) {
tree[pl].zero = tree[pr].zero = 1;
tree[pl].one = tree[pr].one = 0;
tree[pl].num = tree[pl].r-tree[pl].l+1;
tree[pr].num = tree[pr].r-tree[pr].l+1;
}
else if (tree[c].one) {
tree[pl].zero = tree[pr].zero = 0;
tree[pl].one = tree[pr].one = 1;
tree[pl].num = tree[pr].num = 0;
}
}
void update (int l, int r, int c, int x, int y, int op) {
if (x > y) return ;
push_down (c);
if (x == l && y == r) {
if (op == 0) {
tree[c].zero = 1;
tree[c].one = 0;
tree[c].num = r-l+1;
}
else {
tree[c].zero = 0;
tree[c].one = 1;
tree[c].num = 0;
}
return ;
}
if (tree[c].mid >= y) update (lson, x, y, op);
else if (tree[c].mid < x) update (rson, x, y, op);
else {
update (lson, x, tree[c].mid, op);
update (rson, tree[c].mid+1, y, op);
}
tree[c].num = tree[pl].num+tree[pr].num;
tree[c].zero = tree[c].one = 0;
}
int query (int l, int r, int c, int x, int y) {
push_down (c);
if (l == x && y == r) {
return tree[c].num;
}
if (tree[c].mid >= y) {
return query (lson, x, y);
}
else if (tree[c].mid < x) {
return query (rson, x, y);
}
else {
return query (lson, x, tree[c].mid)+query (rson, tree[c].mid+1, y);
}
}
bool ok (int x) {
for (int i = 1; i <= n; i++) b[i] = (a[i]>x);
build_tree (1, n, 1);
for (int i = 1; i <= m; i++) { //cout << i << endl;
int tot1 = query (1, n, 1, op[i][1], op[i][2]);//0的数量
int tot2 = op[i][2]-op[i][1]+1-tot1;//1的数量
if (op[i][0] == 1) {
update (1, n, 1, op[i][1], op[i][1]+tot2-1, 1);
update (1, n, 1, op[i][2]-tot1+1, op[i][2], 0);
}
else {
update (1, n, 1, op[i][1], op[i][1]+tot1-1, 0);
update (1, n, 1, op[i][2]-tot2+1, op[i][2], 1);
}
}
int res = query (1, n, 1, k, k);
return res^1;
}
int main () {
//freopen ("more.in", "r", stdin);
int t;
scanf ("%d", &t);
while (t--) {
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", &op[i][0], &op[i][1], &op[i][2]);
scanf ("%d", &k);
int l = 1, r = n;
while (r-l > 1) {
int mid = (l+r)>>1;
if (ok (mid)) l = mid;
else r = mid;
}
printf ("%d\n", ok (l) ? r : l);
}
return 0;
}