郁闷的出纳员 ( splay )

题意 :  出纳员管理员工的信息 , 有几种命令



思路 : 对于 A 和 S 操作 , 其实不用更新整棵树的信息 , 而是只要对应的改变 min 就可以了 。

查找第 k 大的时候 , 应为工资可能会相同 , 所以要维护一个 cnt 域 , 光只有sz 域不够

删除的话 , 我是自己写了个 lower_bound , 然后把要删除的东西放到 keyTree 删掉

另外如果刚进来就是小于最低工资的 , 直接无视


#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define MAXN 100005
#define keyNode ( ch[ch[root][1]][0] ) 
#define ls(x) ( ch[x][0] ) 
#define rs(x) ( ch[x][1] )
#define wh(x,y) (rs(y)==x)
#define INF 0x3f3f3f3f

struct Splay{
	int tot ;
	int sz[MAXN] ;
	int top ;
	int val[MAXN] ;
	int s[MAXN] ;
	int pre[MAXN] ;
	int ch[MAXN][2] ;
	int cnt[MAXN] ;
	int root ;

	void Rotate( int x , int op ){ 
		int y = pre[x] ;
		pushdown(y) ;
		pushdown(x) ;
		if( pre[y] ) {
			ch[pre[y]][wh(y,pre[y])] = x ;
		}
		pre[x] = pre[y] ;
		pre[y] = x ;
		ch[y][op] = ch[x][op^1] ;
		if( ch[x][op^1] ) {
			pre[ch[x][op^1]] = y ;
		}
		ch[x][op^1] = y ;
		pushup(y) ;
	}

	void splay( int x , int goal ){
		pushdown( x ) ;
		while( pre[x] != goal ) {
			int y = pre[x] ;
			if( pre[y] == goal ) {
				Rotate( x , wh( x , y ) ) ;
			}else{
				int op = wh( x , y ) ;
				if( wh( y , pre[y] ) == op ) {
					Rotate( y , op ) ;
					Rotate( x , op ) ;
				}else{
					Rotate( x , op ) ;
					Rotate( x , op^1 ) ;
				}
			}
		}
		pushup( x ) ;
		if( goal == 0 ) root = x ;
	}
	void debug( int x ){
		if( x ) {
			printf( " x = %d lson = %d rson = %d pre = %d val = %d sz = %d cnt = %d \n" , x , ls(x) , rs(x) , pre[x] , val[x] , sz[x] , cnt[x] ) ;
			debug( ls(x) ) ;
			debug( rs(x) ) ;
		}
	}
	void del( int x ){
		if( x ) {
			s[top++] = x ;
			del(ls(x)) ;
			del(rs(x)) ;
		}
	}
	void erase( int x ){
		if( x == 0 ) return ;
		int fa = pre[x] ;
		ch[fa][wh(x,fa)] = 0 ;
		del( x ) ;
		pushup( fa ) ;
	}
	void pushdown( int x ){}
	void pushup( int x ){
		sz[x] = sz[ls(x)] + sz[rs(x)] + cnt[x] ;
	}
	void makenode( int &x , int fa , int Sz , int v ){
		if( top ) 
			x = s[--top] ;
		else
			x = tot ++ ;
		pre[x] = fa ;
		sz[x] = Sz ;
		cnt[x] = Sz ;
		val[x] = v ;
		ls(x) = rs(x) = 0 ;
	}
	void init(){
		tot = 0 ;
		top = 0 ;
		makenode( root , 0 , 0 , 0 ) ;
		makenode( root , 0 , 1 , -INF ) ;
		makenode( rs(root) , root , 1 , INF ) ;
		pushup( root ) ;
	}
	int size(){
		return sz[root] - 2 ;
	}
	int findk( int k ){ 
		int x = root ;
		k = size() - k + 1 ;
		if( k <= 0 ) return -1 ;
		pushdown(x) ;
		while( true ) {
			if( sz[ls(x)] > k ) {
				x = ls(x) ;
			}else{
				k -= sz[ls(x)] + cnt[x] ;
				if( k < 0 ) break;
				x = rs(x) ;
			}
			pushdown( x ) ;
		}
		return val[x] ;
	}
	void insert( int v ){ 
		int x = root ;
		pushdown( x ) ;
		while( ch[x][v>val[x]] ) {
			if( v == val[x] ) {
				sz[x] ++ ;
				cnt[x] ++ ;
				splay( x , 0 ) ;
				return ;
			}
			x = ch[x][v>val[x]] ;
			pushdown( x ) ;
 		}
		makenode( ch[x][v>val[x]] , x , 1 , v ) ;
		splay( ch[x][v>val[x]] , 0 ) ;
	}

	int lower_bound( int key ) {
		int x = root ;
		pushdown(x) ;
		int ans = -1 ;
		while( x ) {
			if( val[x] >= key ) {
				ans = x ;
				x = ls(x) ;
			}else{
				x = rs(x) ;
			}
			pushdown( x ) ;
		}
		return ans ;
	}

	void remove( int Min ){
		// 找到第一个大于等于 Min 的数
		int key = lower_bound( Min ) ;
		splay( 1 , 0 ) ;
		splay( key , root ) ;
		erase( keyNode ) ;
		pushup( root ) ;
	}

}s ;

int main(){
	int n , Min ;
	while( scanf( "%d%d" , &n , &Min ) != EOF ) {
		s.init() ;
		//s.debug( s.root ) ;
		int change = 0 ;
		int left = 0 ;

		for( int i = 1 ; i <= n ; i ++ ) {
			char op[15] ;
			scanf( "%s" , op ) ;
			if( op[0] == 'I' ) {
				int v ;
				scanf( "%d" , &v ) ;
				v -= change ;
				if( v < Min ) continue ;
				s.insert( v ) ;
			}else if( op[0] == 'A' ) {
				int k ; scanf( "%d" , &k ) ;
				Min -= k ;
				change += k ;
			}else if( op[0] == 'S' ) {
				int k ;
				scanf( "%d" , &k ) ;
				Min += k ;
				change -= k ;
				int tmp = s.size() ;
				s.remove( Min ) ;
				left += tmp - s.size() ;
			}else{
				int k ;
				scanf( "%d" , &k ) ;
				int ans = s.findk(k) ;
				if( ans == -1 ) 
					puts( "-1" ) ;
				else
					printf( "%d\n" , ans + change ) ;
			}
			//s.debug( s.root ) ;
		}
		printf( "%d\n" , left ) ;
	}
	return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值