[TJOI2016]排序——[線段樹]

在這裏插入圖片描述
【題意分析】

首先,暴力sort有30pts…

全排列是一個特別好的性質,我們想想有沒有特別的做法。

由於數字保證不重複,對於x,把大於等於x的數全部變爲1,把小於x的數全部變成0。

那麼我們可以發現:對於要排序的區間[l,r],如果是升序,那麼區間前面肯定是若干個零,後面全是1,如果是降序,那麼區間前面全都是1, 後面全都是0。

然後這樣操作之後我們看看要求的q位置上數字是否爲1,就可以初步確定排完後這個位置上的數比x大還是比x小。(1是比x大,0是比x小)

想到什麼?二分這個x,二分到最後無法再放縮時,說明我們已經找到了答案。

現在唯一的問題就是排序,由於序列全是0和1,我們可以考慮用線段樹維護:利用線段樹可以求出每段區間有幾個0與幾個1(區間求和就可以算出幾個1),排序時,只要一段一段地賦值即可。

具體操作:對於區間[l,r][l,r]有res個1,那麼如果是降序,[l,l+res1][l,l+res-1]爲1,[l+res,r][l+res,r]爲0.
如果是升序,[l,rres][l,r-res]爲0,[rres+1,r][r-res+1,r]爲1

Code :

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 200000
using namespace std;

struct Node {
	int opt, l, r;
}ques[MAXN];

int tree[MAXN << 2], lazy[MAXN << 2], a[MAXN], b[MAXN], n, q, res, pos, ans;

inline int read () {
	register int s = 0, w = 1;
	register char ch = getchar ();
	while (! isdigit (ch)) {if (ch == '-') w = -1; ch = getchar ();}
	while (isdigit (ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar ();}
	return s * w;
}

inline void pushup (int now) {
	tree[now] = tree[now << 1] + tree[now << 1 | 1];
}

inline void pushdown (int now, int L, int R) {
	int mid = L + R >> 1;
	tree[now << 1] = lazy[now] * (mid - L + 1);
	tree[now << 1 | 1] = lazy[now] * (R - mid);
	lazy[now << 1] = lazy[now];
	lazy[now << 1 | 1] = lazy[now];
	lazy[now] = -1;
}

void build (int now, int l, int r) {
	lazy[now] = -1;
	if (l == r) {tree[now] = b[l]; return;}
	int mid = l + r >> 1;
	build (now << 1, l, mid);
	build (now << 1 | 1, mid + 1, r);
	pushup (now);
}

void update (int now, int l, int r, int L, int R, int k) {
	if (R < l || r < L) return;
	if (L <= l && r <= R) {tree[now] = (r - l + 1) * k, lazy[now] = k; return;}
	if (lazy[now] != -1) pushdown (now, l, r);
	int mid = l + r >> 1;
	update (now << 1, l, mid, L, R, k);
	update (now << 1 | 1, mid + 1, r, L, R, k);
	pushup (now);
}

void query (int now, int l, int r, int L, int R) {
	if (R < l || r < L) return;
	if (L <= l && r <= R) {res += tree[now]; return;}
	if (lazy[now] != -1) pushdown (now, l, r);
	int mid = l + r >> 1;
	query (now << 1, l, mid, L, R);
	query (now << 1 | 1, mid + 1, r, L, R);
}

inline bool check (int x) {
	for (register int i = 1; i <= n; i++) b[i] = (a[i] >= x);
	memset (tree, 0, sizeof tree), build (1, 1, n);
	query (1, 1, n, 1, 1);
	for (register int i = 1; i <= q; i++) {
		res = 0, query (1, 1, n, ques[i].l, ques[i].r);
		if (ques[i].opt == 0) {
			update (1, 1, n, ques[i].l, ques[i].r - res, 0);
			update (1, 1, n, ques[i].r - res + 1, ques[i].r, 1);
		}
		else {
			update (1, 1, n, ques[i].l, ques[i].l + res - 1, 1);
			update (1, 1, n, ques[i].l + res, ques[i].r, 0);
		}
	}
	res = 0, query (1, 1, n, pos, pos);	return res;
}

int main () {
	n = read (), q = read ();
	for (register int i = 1; i <= n; i++) a[i] = read ();
	for (register int i = 1; i <= q; i++) ques[i].opt = read (), ques[i].l = read (), ques[i].r = read ();
	pos = read (); int L = 1, R = n;
	while (L <= R) {
		int mid = L + R >> 1;
		if (check (mid)) ans = mid, L = mid + 1;
		else R = mid - 1;
	}
	return printf ("%d\n", ans), 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章