[bzoj4552][Tjoi2016&Heoi2016]排序 二分+線段樹

4552: [Tjoi2016&Heoi2016]排序

Time Limit: 60 Sec  Memory Limit: 256 MB
[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

HINT

對於這道題,我們二分一個權值,大於等於這個權值就爲1,否則爲0
01線段樹排序很簡單,大家都會
最後判斷這一位是否是1
這種煞筆線段樹都花了我半個多小時。。
#include <bits/stdc++.h>
const int N = 1e5 + 5;
int sum[N<<2], flag[N<<2], jzm_naive, a[N], opt[N], lf[N], rg[N], q, n, m, ans;
void update( int k ){ sum[k] = sum[k<<1] + sum[k<<1|1]; }
void pushdown( int k, int l, int r ){
	if( flag[k] != -1 ){
		int mid = l + r >> 1;
		sum[k<<1] = ( mid - l + 1 ) * flag[k];
		sum[k<<1|1] = ( r - mid ) * flag[k];
		flag[k<<1] = flag[k<<1|1] = flag[k];
		flag[k] = -1;
	}
}
void build( int k, int l, int r ){
	flag[k] = -1;
	if( l == r ){
		sum[k] = ( a[l] >= jzm_naive );
		return ;
	}
	int mid = l + r >> 1;
	build( k<<1, l, mid );
	build( k<<1|1, mid + 1, r );
	update( k );
}
void modify( int k, int l, int r, int L, int R, int x ){
	if( L > R ) return ;
	if( L <= l && r <= R ){
		sum[k] = ( r - l + 1 ) * x; flag[k] = x;
		return ;
	}
	pushdown( k, l, r );
	int mid = l + r >> 1;
	if( L <= mid ) modify( k<<1, l, mid, L, R, x );
	if( R >  mid ) modify( k<<1|1, mid + 1, r, L, R, x );
	update( k );
}
int query( int k, int l, int r, int L, int R ){
	if( L <= l && r <= R ) return sum[k];
	pushdown( k, l, r );
	int mid = l + r >> 1, res = 0;
	if( L <= mid ) res += query( k<<1, l, mid, L, R );
	if( R >  mid ) res += query( k<<1|1, mid + 1, r, L, R );
	return res;
}
bool check( int x ){
	jzm_naive = x;
	build( 1, 1, n );
	for( int i = 1; i <= m; i++ ){
		int tum = query( 1, 1, n, lf[i], rg[i] );
		if( opt[i] == 0 ){
			modify( 1, 1, n, lf[i], rg[i] - tum, 0 );
			modify( 1, 1, n, rg[i] - tum + 1, rg[i], 1 );
		}else{
			modify( 1, 1, n, lf[i], lf[i] + tum - 1, 1 );
			modify( 1, 1, n, lf[i] + tum, rg[i], 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", &opt[i], &lf[i], &rg[i] );
	scanf( "%d", &q );
	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;
	}
	printf( "%d\n", ans );
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章