Loading

splay学习

先记录一下我自己打的\(splay\)模板(综合多个\(blog\),巨简洁)
甚至我自己加入了自动机元素(在\(x\)节点值为\(dlt\)应该到达哪个儿子)
好写好调,墙烈案例

ps. 需要注意的:

  • \(spinup\)中的\(z\)\(ch [z][sk(y)]\),而不是\(ch [z][k]\)
  • 只要有\(size\)改动就要\(splay\)维护\(size\)正确性
  • 只要没事就要\(splay\) 一下。
code
#include <cstring>
#include <algorithm>
#include <cstdio>
#define mp make_pair
#define R register int
#define int long 
#define printf Ruusupuu = printf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
typedef pair< int , int > PI ;
const int N = 1e5 + 10 ;
const int Inf = 0x3f3f3f3f ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

int n , opt ;
int root , znt , ch [N][2] , fa [N] , son [N] , val [N] , size [N] ;

#define zt( x ) son [x] = ( son [ch [x][0]] + son [ch [x][1]] + size [x] ) 
#define sk( x ) ( x == ch [fa [x]][1] )
#define tr( x , dlt ) ch [x][dlt > val [x]] 

inline void spinup( int x ){
	R y = fa [x] , z = fa [y] , k = sk( x ) ;
	ch [z][sk(y)] = x , fa [x] = z ;
	ch [y][k] = ch [x][k ^ 1] , fa [ch [x][k ^ 1]] = y ;
	ch [x][k ^ 1] = y , fa [y] = x ;
	zt( y ) , zt( x ) ;
}  

inline void splay( int x , int pos ){
	while( fa [x] != pos ){
		R y = fa [x] ; R z = fa [y] ;
		if( z != pos ) sk( x ) ^ sk ( y ) ? spinup( x ) : spinup( y ) ; //on the same line ? spinup( y ) : spinup( x ) ;
		spinup( x ) ; 
	} if( !pos ) root = x ;
}

inline void ins( int dlt ){
	R now = root , fh = 0 ;
	while( now && val [now] != dlt ) fh = now , now = tr( now , dlt ) ; 	 
	if( now ) size [now] ++ ;
	else {
		now = ++ znt ;
		if( fh ) tr( fh , dlt ) = now ; 
		size [now] = son [now] = 1 ;
		fa [now] = fh , val [now] = dlt ; 
	}
	splay( now , 0 ) ;
} 

inline void find( int dlt ){
	R now = root ; if( !now ) return ;
	while( tr( now , dlt ) && val [now] != dlt ) 
		now = tr( now , dlt ) ;
	splay( now , 0 ) ;
}

inline int ngr( int dlt , bool fg ){
	find( dlt ) ; R now = root ;
	if( val [now] != dlt && ( fg ^ ( val [now] < dlt ) ) ) return now ; 
	now = ch [now][fg] ;
	while( ch [now][fg ^ 1] ) now = ch [now][fg ^ 1] ;
	return now ;
}

inline void del( int dlt ){
	int pre = ngr( dlt , 0 ) , nxt = ngr( dlt , 1 ) ;
	splay( pre , 0 ) , splay( nxt , pre ) ; 
	int now = ch [nxt][0] ;
	if( size [now] > 1 ) size [now] -- , splay( now , 0 ) ; 
 	else ch [nxt][0] = 0 , splay( nxt , 0 ) ;	
}

inline int rk( int rank ){
	int now = root ;
	if( son [now] < rank ) return 0 ;
	while( 1 ){
		int nxt = ch [now][0] ;
		if( size [now] + son [nxt] < rank ) rank -= ( size [now] + son [nxt] ) , now = ch [now][1] ;
		else if( son [nxt] >= rank ) now = nxt ;
		else { splay( now , 0 ) ; return val [now] ; } 	 	
	} 
}

void sc(){
	n = read() ;
}

void work(){
	ins( -Inf ) , ins( Inf ) ; 
	while( n -- ){
		opt = read() ;
		if( opt == 1 ) ins( read() ) ;
		else if( opt == 2 ) del( read() ) ;
		else if( opt == 3 ) find( read() ) , printf( "%ld\n" , son [ch [root][0]] ) ;
		else if( opt == 4 ) printf( "%ld\n" , rk( read() + 1 ) ) ;
		else if( opt == 5 ) printf( "%ld\n" , val [ngr( read() , 0 )] ) ;
		else if( opt == 6 ) printf( "%ld\n" , val [ngr( read() , 1 )] ) ;
	}
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
} 

应某大佬觉得我的板子过不了数据加强版,所以更新了一下,其实很简单,只需要额外写一个函数\(ranks\),因为\(find\)函数如果找不到对应的值,就会把这个值的前驱或者后继搞到根,所以只需要特判一下就行了。

其实两份代码的差别只有一个函数

inline int ranks( int dlt ){
	find( dlt ) ;
	R now = root ;
	if( val [now] < dlt ) now = ngr( val [now] , 1 ) ;
	return son [ch [now][0]] ;
}
code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register int
#define int long
#define scanf Ruusupuu = scanf 
#define printf Ruusupuu = printf
#define freopen rsp_5u = freopen

int Ruusupuu ;
FILE * rsp_5u ;

using namespace std ;
typedef long long L ;
typedef double D ;
const int N = 2e6 + 10 ;
const int Inf = 1 << 30 ;

inline void of(){ freopen( "in.in" , "r" , stdin ) , freopen( "out.out" , "w" , stdout ) ; }
inline void cf(){ fclose( stdin ) , fclose( stdout ) ; }
inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

int n , m , opt , x , last , ans ; 

int size [N] , son [N] , val [N] , fa [N] , ch [N][2] , root , znt ;

#define zt( x ) son [x] = son [ch [x][0]] + son [ch [x][1]] + size [x] 
#define sk( x ) ( x == ch [fa [x]][1] )
#define tr( x , dlt ) ch [x][dlt > val [x]]

inline void spinup( int x ){
	R y = fa [x] , z = fa [y] , k = sk( x ) ;
	ch [z][sk(y)] = x , fa [x] = z ;
	ch [y][k] = ch [x][k ^ 1] , fa [ch [x][k ^ 1]] = y ; 
	ch [x][k ^ 1] = y , fa [y] = x ;
	zt( y ) , zt( x ) ;
} 

inline void splay( int x , int pos ){
	while( fa [x] != pos ){
		R y = fa [x] , z = fa [y] ;
		if( z != pos ) sk( x ) ^ sk( y ) ? spinup( x ) : spinup( y ) ;
		spinup( x ) ; 
	} if( !pos ) root = x ;
}
 
inline void ins( int dlt ){
	R now = root , fh = 0 ; 
	while( now && val [now] != dlt ) fh = now , now = tr( now , dlt ) ;
	if( now ) size [now] ++ ;
	else{
		now = ++ znt ;
		if( fh ) tr( fh , dlt ) = now ;
		fa [now] = fh , val [now] = dlt ;
		son [now] = size [now] = 1 ;
	} splay( now , 0 ) ;
} 
 
inline void find( int dlt ){ 
	R now = root ;
	while( tr( now , dlt ) && val [now] != dlt ) now = tr( now , dlt ) ;
	splay( now , 0 ) ; 
} 

inline int ngr( int dlt , bool fg ){
	find( dlt ) ; R now = root ;
	if( val [now] != dlt && ( fg ^ ( dlt > val [now] ) ) ) return splay( now , 0 ) , now ;
	now = ch [now][fg] ;
	while( ch [now][fg ^ 1] ) now = ch [now][fg ^ 1] ;
	return splay( now , 0 ) , now ;
}

inline void del( int dlt ){
	int pre = ngr( dlt , 0 ) , nxt = ngr( dlt , 1 ) ;
	splay( pre , 0 ) , splay( nxt , pre ) ;
	if( size [ch [nxt][0]] > 1 ) size [ch [nxt][0]] -- , splay( ch [nxt][0] , 0 ) ;
	else ch [nxt][0] = 0 , splay( nxt , 0 ) ;  
}

inline int ranks( int dlt ){
	find( dlt ) ;
	R now = root ;
	if( val [now] < dlt ) now = ngr( val [now] , 1 ) ;
	return son [ch [now][0]] ;
}

inline int rk( int rank ){
	R now = root ;
	while( 1 ){
		R nxt = ch [now][0] ;
		if( size [now] + son [nxt] < rank ) rank -= ( size [now] + son [nxt] ) , now = ch [now][1] ;
		else if( son [nxt] >= rank ) now = nxt ;
		else return splay( now , 0 ) , now ;
	}
}

void sc(){
	n = read() , m = read() ;
	for( R i = 1 ; i <= n ; i ++ ) ins( read() ) ;
}
 
void work(){
	ins( Inf ) , ins( -Inf ) ;
	while( m -- ){
		opt = read() , x = read() ^ last ;
//		printf( "%ld %ld\n" , opt , x ) ;
		if( opt == 1 ) ins( x ) ;
		else if( opt == 2 ) del( x ) ;
		else if( opt == 3 ) ans ^= ( last = ranks( x ) ) ;
		else if( opt == 4 ) ans ^= ( last = val [rk( x + 1 )] ) ;
		else if( opt == 5 ) ans ^= ( last = val [ngr( x , 0 )] ) ;
		else if( opt == 6 ) ans ^= ( last = val [ngr( x , 1 )] ) ;
	} printf( "%ld\n" , ans ) ;
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
}

由于这个东西只能写一颗,所以我把它搞到结构体里面了,这样他不好看了,但是好用了。
只需要在所有的东西前面加一个splay.就可以了

code 2.0版
#include <cstring>
#include <algorithm>
#include <cstdio>
#define mp make_pair
#define R register int
#define int long 
#define printf Ruusupuu = printf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
typedef pair< int , int > PI ;
const int N = 1e5 + 10 ;
const int Inf = 0x3f3f3f3f ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

int n , opt ;

struct Splay{

	int root , znt , ch [N][2] , fa [N] , son [N] , val [N] , size [N] ;

	#define zt( x ) son [x] = ( son [ch [x][0]] + son [ch [x][1]] + size [x] ) 
	#define sk( x ) ( x == ch [fa [x]][1] )
	#define tr( x , dlt ) ch [x][dlt > val [x]] 

	inline void spinup( int x ){
		R y = fa [x] , z = fa [y] , k = sk( x ) ;
		ch [z][sk(y)] = x , fa [x] = z ;
		ch [y][k] = ch [x][k ^ 1] , fa [ch [x][k ^ 1]] = y ;
		ch [x][k ^ 1] = y , fa [y] = x ;
		zt( y ) , zt( x ) ;
	}  

	inline void splay( int x , int pos ){
		while( fa [x] != pos ){
			R y = fa [x] ; R z = fa [y] ;
			if( z != pos ) sk( x ) ^ sk ( y ) ? spinup( x ) : spinup( y ) ; //on the same line ? spinup( y ) : spinup( x ) ;
			spinup( x ) ; 
		} if( !pos ) root = x ;
	}

	inline void ins( int dlt ){
		R now = root , fh = 0 ;
		while( now && val [now] != dlt ) fh = now , now = tr( now , dlt ) ; 	 
		if( now ) size [now] ++ ;
		else {
			now = ++ znt ;
			if( fh ) tr( fh , dlt ) = now ; 
			size [now] = son [now] = 1 ;
			fa [now] = fh , val [now] = dlt ; 
		}
		splay( now , 0 ) ;
	} 

	inline void find( int dlt ){
		R now = root ; if( !now ) return ;
		while( tr( now , dlt ) && val [now] != dlt ) 
			now = tr( now , dlt ) ;
		splay( now , 0 ) ;
	}

	inline int ngr( int dlt , bool fg ){
		find( dlt ) ; R now = root ;
		if( val [now] != dlt && ( fg ^ ( val [now] < dlt ) ) ) return now ; 
		now = ch [now][fg] ;
		while( ch [now][fg ^ 1] ) now = ch [now][fg ^ 1] ;
		return now ;
	}

	inline void del( int dlt ){
		int pre = ngr( dlt , 0 ) , nxt = ngr( dlt , 1 ) ;
		splay( pre , 0 ) , splay( nxt , pre ) ; 
		int now = ch [nxt][0] ;
		if( size [now] > 1 ) size [now] -- , splay( now , 0 ) ; 
	 	else ch [nxt][0] = 0 ;	
	}

	inline int rk( int rank ){
		int now = root ;
		if( son [now] < rank ) return 0 ;
		while( 1 ){
			int nxt = ch [now][0] ;
			if( size [now] + son [nxt] < rank ) rank -= ( size [now] + son [nxt] ) , now = ch [now][1] ;
			else if( son [nxt] >= rank ) now = nxt ;
			else return val [now] ;  	 	
		} 
	}
}splay ;

void sc(){
	n = read() ;
}

void work(){
	splay.ins( -Inf ) , splay.ins( Inf ) ; 
	while( n -- ){
		opt = read() ;
		if( opt == 1 ) splay.ins( read() ) ;
		else if( opt == 2 ) splay.del( read() ) ;
		else if( opt == 3 ) splay.find( read() ) , printf( "%ld\n" , splay.son [splay.ch [splay.root][0]] ) ;
		else if( opt == 4 ) printf( "%ld\n" , splay.rk( read() + 1 ) ) ;
		else if( opt == 5 ) printf( "%ld\n" , splay.val [splay.ngr( read() , 0 )] ) ;
		else if( opt == 6 ) printf( "%ld\n" , splay.val [splay.ngr( read() , 1 )] ) ;
	}
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
} 

\(\mathtt {zbw}\)要求,更新一个区间提取(分裂),但是话说,这不是区间操作吗?

先贴一个区间问题入门,建议先阅读再接着看,我的博客\(splay\)区间入门:文艺平衡树和火星人

\(splay\)区间处理主要靠的是标记,和线段树中的标记一样,查询的时候并不需要全部下传。

这也就意味着,如果我们存储一个关于的答案的值域的话,传标记的时候要一并把答案域更新。

每次\(splay\)之前,最好把所有标记全部下传。

这只需要在\(splay\)前面加一句话,写一个函数。

void spall( int x ){ if( fa [x] != root && fa [x] != 0 ) spall( fa [x] ) ; sp( x ) ; }
inline void splay( int x , int pos ){
	spall( x ) ;
	while( fa [x] != pos ){
		R y = fa [x] , z = fa [y] ;
		if( z != pos ) sk( x ) ^ sk( y ) ? spinup( x ) : spinup( y ) ;
		spinup( x ) ; 
	} if( !pos ) root = x ;
}

注意\(spall\)这个函数实在回溯的时候下传标记的,保证了标记从根传到底。

小结一下:\(splay\)标记有关注意

  • 每次下传标记都要保证子节点信息域和答案域均正确
  • 每次有从上到下的遍历的时候必须下传标记
  • \(splay\)之前最好下传标记

\(splay\)提取一个区间,我们可以把这个区间转出来,然后把他从树上割下来(把\(ch[fa[x][...]]\)设置成\(0\)
具体进阶推荐看这两篇提接以加深理解。
最长上升子序列星际旅行

二逼平衡树先咕一下...

upd 2021.7.25

二逼平衡树更新啦,我自己的写法好像和众多写法不太一样,并且非常慢,非常费空间。
我是真的给每个节点都开一个\(splay\)
所以空间需要开动态的。
删除需要回收空间。
但是写起来很方便。

操作一就是在每个区间找有多少个比他小的数。
操作二二分答案变操作一。
操作三先删后加。
操作四,操作五都是对小于/大于他的取\(min,max\)就行了。

code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register int
#define scanf Ruusupuu = scanf 
#define printf Ruusupuu = printf
#define freopen rsp_5u = freopen

int Ruusupuu ;
FILE * rsp_5u ;

using namespace std ;
typedef long long L ;
typedef double D ;
const int N = 5e4 + 10 ;
const int Inf = 2147483647 ;

inline void of(){ freopen( "in.in" , "r" , stdin ) , freopen( "out.out" , "w" , stdout ) ; }
inline void cf(){ fclose( stdin ) , fclose( stdout ) ; }
inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

int n , m , opt ;

struct Splay{
	int root , znt , *fa , **ch , *son , *size , *val , *pool , top ;
	
	inline void Size( int x ){
		fa = new int [x] ;
		son = new int [x] ;
		size = new int [x] ;
		val = new int [x] ;
		ch = new int *[x] ;
		pool = new int [x] ;
		for( R i = 0 ; i < x ; i ++ ) ch [i] = new int [2] ;
	}
	
	#define zt( x ) son [x] = son [ch [x][0]] + son [ch [x][1]] + size [x] 
	#define sk( x ) ( x == ch [fa [x]][1] ) 
	#define tr( x , dlt ) ch [x][dlt > val [x]]
	
	inline void spinup( int x ){
		R y = fa [x] , z = fa [y] , k = sk( x ) ;
		ch [z][sk(y)] = x , fa [x] = z ;
		ch [y][k] = ch [x][k ^ 1] , fa [ch [x][k ^ 1]] = y ;
		ch [x][k ^ 1] = y , fa [y] = x ;
		zt( y ) , zt( x ) ;   
	}

	inline void splay( int x , int pos ){
		while( fa [x] != pos ){
			R y = fa [x] , z = fa [y] ;
			if( z != pos ) sk( x ) ^ sk( y ) ? spinup( x ) : spinup( y ) ;
			spinup( x ) ;
		} if( !pos ) root = x ;
	}
	
	inline void ins( int dlt ){
		R now = root , fh = 0 ;
		while( now && val [now] != dlt ) fh = now , now = tr( now , dlt ) ;
		if( now ) size [now] ++ ;
		else{
			now = ( top ) ? ( pool [top --] ) : ( ++ znt ) ;
			if( fh ) tr( fh , dlt ) = now ;
			fa [now] = fh , val [now] = dlt ;
			son [now] = size [now] = 1 ;
		} splay( now , 0 ) ;
	}
	
	inline void find( int dlt ){
		R now = root ;
		while( tr( now , dlt ) && val [now] != dlt ) now = tr( now , dlt ) ;
		splay( now , 0 ) ;
	}
	
	inline int ngr( int dlt , bool fg ){
		find( dlt ) ; R now = root ;
		if( val [now] != dlt && ( fg ^ ( dlt > val [now] ) ) ) return splay( now , 0 ) , now ;
		now = ch [now][fg] ;
		while( ch [now][fg ^ 1] ) now = ch [now][fg ^ 1] ;
		return splay( now , 0 ) , now ; 
	}
	
	inline void del( int dlt ){
		R pre = ngr( dlt , 0 ) , nxt = ngr( dlt , 1 ) ;
		splay( pre , 0 ) , splay( nxt , pre ) ;
		if( size [ch [nxt][0]] > 1 ) size [ch [nxt][0]] -- , splay( ch [nxt][0] , 0 ) ;
		else pool [++ top] = ch [nxt][0] , ch [nxt][0] = 0 , splay( nxt , 0 ) ;  
	}
	
	inline int rk( int rank ){
		R now = root ;
		while( 1 ){
			R nxt = ch [now][0] ;
			if( son [nxt] + size [now] < rank ) rank -= ( son [nxt] + size [now] ) , now = ch [now][1] ;
			else if( son [nxt] >= rank ) now = nxt ;
			else return splay( now , 0 ) , now ;
		}
	}
	
	inline int ranks( int dlt ){
		find( dlt ) ;
		R now = root ; 
		if( val [now] < dlt ) now = ngr( val [now] , 1 ) ;
		return son [ch [now][0]] - 1 ;
	}

	inline int rks( int dlt ){
		find( dlt ) ;
		R now = root ; 
		if( val [now] < dlt ) now = ngr( val [now] , 1 ) ;
		return son [ch [now][0]] - 1 + ( ( val [now] == dlt ) ? size [now] : 0 ) ;
	}
} ;

struct Ts{ int l , r ; Splay data ; } t [N << 2] ;
int lx , rx , pos , dlt , plt ;

void buid( int x , int l , int r ){
	t [x].l = l , t [x].r = r ;
	t [x].data.Size( r - l + 4 ) ;
//	printf( "ASKSPACE%d %d %d %d\n" , x , l , r , r - l + 4 ) ;
	t [x].data.ins( -Inf ) , t [x].data.ins( Inf ) ;
	if( l == r ) return ;
	int mid = ( l + r ) >> 1 ;
	buid( x << 1 , l , mid ) ;
	buid( x << 1 | 1 , mid + 1 , r ) ;
} 

void ins( int x ){
	t [x].data.ins( dlt ) ;
//	printf( "USING%d %d %d\n" , t [x].l , t [x].r , x ) ;
	if( t [x].l == t [x].r ) return ;
	int mid = ( t [x].l + t [x].r ) >> 1 ;
	if( pos <= mid ) ins( x << 1 ) ;
	else ins( x << 1 | 1 ) ;
}

void del( int x ){
	t [x].data.del( dlt ) ;
	if( t [x].l == t [x].r ) return ;
	int mid = ( t [x].l + t [x].r ) >> 1 ;
	if( pos <= mid ) del( x << 1 ) ;
	else del( x << 1 | 1 ) ;
}

int askone( int x ){
	if( t [x].l == t [x].r ) return t [x].data.val [t [x].data.rk( 2 )] ;
	int mid = ( t [x].l + t [x].r ) >> 1 ;
	if( pos <= mid ) return askone( x << 1 ) ;
	else return askone( x << 1 | 1 ) ;
}

inline void upd(){
	dlt = askone( 1 ) , del( 1 ) ;
	dlt = read() , ins( 1 ) ;
}

int Askrank( int x ){
	if( t [x].l >= lx && t [x].r <= rx ) return t [x].data.ranks( dlt ) ;
	int mid = ( t [x].l + t [x].r ) >> 1 , ans = 0 ;
	if( lx <= mid ) ans += Askrank( x << 1 ) ;
	if( rx > mid ) ans += Askrank( x << 1 | 1 ) ;
	return ans ; 
}

inline int Boundans(){
//	puts( "BOUND" ) ;
	int lside = 0 , rside = 1e8 + 10 , ans = 0 ;
	while( lside <= rside ){
		dlt = ( lside + rside ) >> 1 ;
	//	printf( "%d %d %d\n" , dlt , plt , Askrank( 1 ) ) ;
		if( Askrank( 1 ) <= plt ) ans = dlt , lside = dlt + 1 ;
		else rside = dlt - 1 ;
	} return ans ;
}

int Askpre( int x ){
	if( t [x].l >= lx && t [x].r <= rx ) return t [x].data.val [t [x].data.ngr( dlt , 0 )] ;
	int mid = ( t [x].l + t [x].r ) >> 1 , ans = -Inf ;
	if( lx <= mid ) ans = max( ans , Askpre( x << 1 ) ) ;
	if( rx > mid ) ans = max( ans , Askpre( x << 1 | 1 ) ) ;
	return ans ; 
}

int Asknxt( int x ){
	if( t [x].l >= lx && t [x].r <= rx ) return t [x].data.val [t [x].data.ngr( dlt , 1 )] ;
	int mid = ( t [x].l + t [x].r ) >> 1 , ans = Inf ;
	if( lx <= mid ) ans = min( ans , Asknxt( x << 1 ) ) ;
	if( rx > mid ) ans = min( ans , Asknxt( x << 1 | 1 ) ) ;
	return ans ;
}

void sc(){	
	n = read() , m = read() ;
	buid( 1 , 1 , n ) ;
	for( R i = 1 ; i <= n ; i ++ ) pos = i , dlt = read() , ins( 1 ) ;
}

void work(){
	while( m -- ){
		opt = read() ;
		if( opt == 1 ) lx = read() , rx = read() , dlt = read() , printf( "%d\n" , Askrank( 1 ) + 1 ) ;		
		else if( opt == 2 ) lx = read() , rx = read() , plt = read() - 1 , printf( "%d\n" , Boundans() ) ;
		else if( opt == 3 ) pos = read() , upd() ;
		else if( opt == 4 ) lx = read() , rx = read() , dlt = read() , printf( "%d\n" , Askpre( 1 ) ) ;
		else if( opt == 5 ) lx = read() , rx = read() , dlt = read() , printf( "%d\n" , Asknxt( 1 ) ) ;
	}
}

signed main(){
	sc() ;
	work() ;
	return 0 ;
}
posted @ 2021-07-07 10:18  Soresen  阅读(90)  评论(2)    收藏  举报