1. 程式人生 > >BZOJ 4552 [Tjoi2016&Heoi2016]排序

BZOJ 4552 [Tjoi2016&Heoi2016]排序

HR 降序排序 二分 update for 進行 %d center OS

4552: [Tjoi2016&Heoi2016]排序

Time Limit: 60 Sec Memory Limit: 256 MB
Submit: 2035 Solved: 1015
[Submit][Status][Discuss]

Description

在2016年,佳媛姐姐喜歡上了數字序列。因而他經常研究關於序列的一些奇奇怪怪的問題,現在他在研究一個難題 ,需要你來幫助他。這個難題是這樣子的:給出一個1到n的全排列,現在對這個全排列序列進行m次局部排序,排 序分為兩種:1:(0,l,r)表示將區間[l,r]的數字升序排序2:(1,l,r)表示將區間[l,r]的數字降序排序最後詢問第q
位置上的數字。

Input

輸入數據的第一行為兩個整數n和m。n表示序列的長度,m表示局部排序的次數。1 <= n, m <= 10^5第二行為n個整 數,表示1到n的一個全排列。接下來輸入m行,每一行有三個整數op, l, r, op為0代表升序排序,op為1代表降序 排序, l, r 表示排序的區間。最後輸入一個整數q,q表示排序完之後詢問的位置, 1 <= q <= n。1 <= n <= 10^5 ,1 <= m <= 10^5

Output

輸出數據僅有一行,一個整數,表示按照順序將全部的部分排序結束後第q位置上的數字。

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5 總結: 考慮二分答案,將問題轉化為判定性問題 可以發現,我們不好直接排序,但是如果是01串,就可以用線段樹維護排序 詢問只有一組q,於是二分最後的答案(mid) 將原數組中大於mid的設為0,小於等於mid的設為1,建立線段樹 然後每次排序,相當於對01串進行排序 最後查詢q位置的數,如果為1,則ans = mid, r = mid - 1否則l = mid + 1
#include <bits/stdc++.h>
using namespace std;

const int maxn = 4e5 + 7;
int sum[maxn], tag[maxn], a[maxn], n;
struct Node {
	int op, l, r;
} q[maxn]; int Q, m;

void update(int o) {
	sum[o] = sum[o << 1] + sum[o << 1 | 1];
}
void pushdown(int o, int l, int r) {
	if(tag[o] != -1) {
		int mid = (l + r) >> 1;
		tag[o << 1] = tag[o]; tag[o << 1 | 1] = tag[o];
		sum[o << 1] = tag[o] * (mid - l + 1);
		sum[o << 1 | 1] = tag[o] * (r - mid); tag[o] = -1; 
	}
}
int Query(int o, int l, int r, int ql, int qr) {
	if(ql <= l && r <= qr) return sum[o];
	int mid = (l + r) >> 1; pushdown(o, l, r);
	int res = 0;
	if(ql <= mid) res += Query(o << 1, l, mid, ql, qr);
	if(qr > mid) res += Query(o << 1 | 1, mid + 1, r, ql, qr);
	return res;
}
void Modify(int o, int l, int r, int ql, int qr, int z) {
	if(ql <= l && r <= qr) {
		sum[o] = z * (r - l + 1); tag[o] = z; return;
	} int mid = (l + r) >> 1; pushdown(o, l, r);
	if(ql <= mid) Modify(o << 1, l, mid, ql, qr, z);
	if(qr > mid) Modify(o << 1 | 1, mid + 1, r, ql, qr, z);
	update(o);
}
void Build(int o, int l, int r, int x) {
	tag[o] = -1;
	if(l == r) {
		sum[o] = (a[l] <= x); return;
	} int mid = (l + r) >> 1;
	Build(o << 1, l, mid, x); Build(o << 1 | 1, mid + 1, r, x);
	update(o);
}
bool check(int x) {
	Build(1, 1, n, x);
	for (int i = 1; i <= m; ++i) {
		int res = Query(1, 1, n, q[i].l, q[i].r);
		if(res == 0 || res == (q[i].r - q[i].l + 1)) continue;
		if(!q[i].op) {
			Modify(1, 1, n, q[i].l, q[i].l + res - 1, 1);
			Modify(1, 1, n, q[i].l + res, q[i].r, 0);
		} else {
			Modify(1, 1, n, q[i].r - res + 1, q[i].r, 1);
			Modify(1, 1, n, q[i].l, q[i].r - res, 0);
		}
	} 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", &q[i].op, &q[i].l, &q[i].r);
	int l = 1, r = n, ans = 0; scanf("%d", &Q);
    while(l <= r) {
    	int mid = (l + r) >> 1;
    	if(check(mid)) {
    		ans = mid; r = mid - 1;
		} else l = mid + 1;
    } printf("%d\n", ans);
	return 0;
}

  

BZOJ 4552 [Tjoi2016&Heoi2016]排序