「Loj #2055」「Tjoi2016」「Heoi2016」排序

Description

JeLix1.png

Hint

\(1\le n,m\le 10^5, q\in[1,n]\)

Solution

如果没有头绪的话,不妨思考一下对于 \(01\) 序列怎么做区间排序操作。

\(\texttt{00000111} \leftarrow \texttt{01010001} \rightarrow \texttt{11100000}\)

这个所谓的排序,只不过就是先数一数这段区间所有的 \(1\) 有几个 \(^{[1]}\),然后将这些 \(1\) 堆到整个区间的前面或后面 \(^{[2]}\)

换句话说……

  • \([1] \rightarrow\) 区间求和
  • \([2] \rightarrow\) 区间赋值

于是成了线段树裸题。


那么我们考虑一下如何把这个神奇的方法应用到这一题上。

假如我们选定了原序列中的一个数 \(t\),那我们要怎么知道这个数是不是答案?

我们记原序列为 \(a\) ,并定义序列 \(b\)\(b_i = [t \le a_i]\) ,即比这个数小的记为 \(0\) ,其他的记为 \(1\)

然后模拟一遍上述的过程。

最后,如果要求的这一位为 \(1\) ,那么真正的答案 \(\text{ans} \ge t\),反之则 \(\text{ans} < t\)

按这个套路显然可以二分优化一下。时间复杂度 \(O(n\log^2 n)\)

Code

#include <iostream>
using namespace std;

const int N = 2e5 + 5;

int sum[N << 2], tag[N << 2];
int L[N << 2], R[N << 2];
#define mid ((L[rt] + R[rt]) >> 1)
#define len(rt) (R[rt] - L[rt] + 1)
inline void pushup(int rt) {
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
inline void pushdown(int rt) {
	if (~tag[rt]) {
		sum[rt << 1] = tag[rt] * len(rt << 1);
		sum[rt << 1 | 1] = tag[rt] * len(rt << 1 | 1);
		tag[rt << 1] = tag[rt << 1 | 1] = tag[rt];
		tag[rt] = -1;
	}
}
void build(int *dat, int l, int r, int rt) {
	L[rt] = l, R[rt] = r, tag[rt] = -1;
	if (l == r) return void(sum[rt] = dat[l]);
	build(dat, l, mid, rt << 1);
	build(dat, mid + 1, r, rt << 1 | 1);
	pushup(rt);
}
int query(int l, int r, int rt) {
	if (l <= L[rt] && R[rt] <= r) return sum[rt];
	pushdown(rt);
	int ret = 0;
	if (l <= mid) ret += query(l, r, rt << 1);
	if (r > mid) ret += query(l, r, rt << 1 | 1);
	return ret;
}
void update(int l, int r, int c, int rt) {
	if (l <= L[rt] && R[rt] <= r) {
		sum[rt] = c * len(rt);
		tag[rt] = c; return;
	}
	pushdown(rt);
	if (l <= mid) update(l, r, c, rt << 1);
	if (r > mid) update(l, r, c, rt << 1 | 1);
	pushup(rt);
}
#undef mid
#undef len

int n, q, k;
struct sortCmd {
	int type;
	int l, r;
} opt[N];
int ary[N], rec[N];

bool judge(int test) {
	for (register int i = 1; i <= n; i ++)
		rec[i] = int(ary[i] >= test);
	build(rec, 1, n, 1);
	for (register int i = 1; i <= q; i ++) {
		int l = opt[i].l, r = opt[i].r;
		int cnt = query(l, r, 1);
		if (opt[i].type) {
			update(l, l + cnt - 1, 1, 1);
			update(l + cnt, r, 0, 1);
		} else {
			update(l, r - cnt, 0, 1);
			update(r - cnt + 1, r, 1, 1);
		}
	}
	return query(k, k, 1);
}

signed main() {
	ios::sync_with_stdio(false);
	cin >> n >> q;
	for (register int i = 1; i <= n; i ++)
		cin >> ary[i];
	for (register int i = 1; i <= q; i ++)
		cin >> opt[i].type >> opt[i].l >> opt[i].r;
	cin >> k;
	
	int ans = 0;
	for (register int l = 1, r = n; l <= r;) {
		int mid = (l + r) >> 1;
		if (judge(mid)) ans = mid, l = mid + 1;
		else r = mid - 1;
	}
	cout << ans << endl;
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/-Wallace-/p/12725538.html