题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5649
n个数的排列,两种操作,一种将[L,R]区间内的数递减排序,另一种将[L,R]中的数递增排序,问最后第k个位置的数字是多少。
好题。
因为最后考虑的只是第k个位置的数字,二分答案。
每次将序列中比x大的都标记为1,其余包括x标记为0,每次排序前,先查询区间中有多少个1和0,然后按照操作将1和0分别更新到区间的左右两部分,用线段树区间更新区间查询即可。判断时如果第k个位置为0则r=m-1,否则l=m+1。
#include
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int MAXN = 1e5 + 10;
int n, q, k;
int a[MAXN], b[MAXN], op[MAXN], LL[MAXN], RR[MAXN];
int C[MAXN << 2], lazy[MAXN << 2];
void pushUp(int rt) {
C[rt] = C[rt << 1] + C[rt << 1 | 1];
}
void pushDown(int rt, int len) {
if (lazy[rt] != -1) {
lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
C[rt << 1] = (len - (len >> 1)) * lazy[rt];
C[rt << 1 | 1] = (len >> 1) * lazy[rt];
lazy[rt] = -1;
}
}
void build(int l, int r, int rt) {
lazy[rt] = -1;
if (l == r) {
C[rt] = a[l];
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushUp(rt);
}
void update(int L, int R, int v, int l, int r, int rt) {
if (L <= l && r <= R) {
C[rt] = v * (r - l + 1);
lazy[rt] = v;
return;
}
pushDown(rt, r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L, R, v, lson);
if (R > m) update(L, R, v, rson);
pushUp(rt);
}
int query(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return C[rt];
pushDown(rt, r - l + 1);
int m = (l + r) >> 1, res = 0;
if (L <= m) res += query(L, R, lson);
if (R > m) res += query(L, R, rson);
return res;
}
int cal(int x) {
for (int i = 1; i <= n; i++) {
a[i] = (b[i] > x);
}
build(1, n, 1);
//cout << C[1] << endl;
for (int i = 1; i <= q; i++) {
int L = LL[i], R = RR[i];
int one = query(L, R, 1, n, 1);
//cout << "(" << L << ", " << R << ") one = " << one << endl;
int zero = R - L + 1 - one;
if (op[i] == 0) {
if (zero > 0) update(L, L + zero - 1, 0, 1, n, 1);
if (one > 0) update(R - one + 1, R, 1, 1, n, 1);
}
else {
if (one > 0) update(L, L + one - 1, 1, 1, n, 1);
if (zero > 0) update(R - zero + 1, R, 0, 1, n, 1);
}
}
return (query(k, k, 1, n, 1) == 0);
}
void solve(int l, int r) {
int res = -1;
while (l <= r) {
int mid = (l + r) >> 1;
int tmp = cal(mid);
//cout << mid << " " << tmp << endl;
if (tmp) {
r = mid - 1;
res = mid;
}
else l = mid + 1;
}
printf("%d\n", res);
}
int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
for (int i = 1; i <= q; i++)
scanf("%d%d%d", &op[i], &LL[i], &RR[i]);
scanf("%d", &k);
solve(1, n);
}
return 0;
}