BZOJ 1861: [Zjoi2006]Book 书架( splay )

splay..

由于想偷懒 , 不想写 insert 和 delete 操作..于是用经典的 reverse 操作 + get 一段区间操作 水过去了.. 无论是 bottom , top 还是 insert , 都相当于两次 reverse

splay 太灵活了..很多题目应该都是怎么乱搞都可以的吧.. 

---------------------------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
 
#define rep( i , n ) for( int i = 0 ; i < n ; ++i )
#define clr( x , c ) memset( x , c , sizeof( x ) )
#define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )
 
using namespace std;
 
const int maxn = 80000 + 5;
const int maxnode = maxn + 100;
 
int seq[ maxn ];
 
struct Node *null , *pt;
 
struct Node {
Node *ch[ 2 ] , *p;
int s , v;
bool rev;
Node( int _v = 0 ) {
v = _v;
ch[ 0 ] = ch[ 1 ] = p = null;
rev = false;
}
inline void setc( Node* c , int d ) {
ch[ d ] = c;
c -> p = this;
}
inline bool d() {
return this == p -> ch[ 1 ];
}
inline void upd() {
s = ch[ 0 ] -> s + ch[ 1 ] -> s + 1;
}
inline void Rev() {
rev ^= 1;
swap( ch[ 0 ] , ch[ 1 ] );
}
inline void relax() {
if( rev ) {
rev = false;
rep( i , 2 ) if( ch[ i ] != null ) 
   ch[ i ] -> Rev();
}
}
void* operator new( size_t ) {
return pt++;
}
};
 
Node NODE[ maxnode ];
Node* root;
Node* V[ maxn ];
 
Node* build( int l , int r ) {
if( l >= r ) return null;
int m = ( l + r ) >> 1;
Node* t = new Node( seq[ m ] );
V[ seq[ m ] ] = t;
t -> setc( build( l , m ) , 0 );
t -> setc( build( m + 1 , r ) , 1 );
t -> upd();
return t;
}
 
void rot( Node* t ) {
Node* p = t -> p;
p -> relax();
t -> relax();
int d = t -> d();
p -> p -> setc( t , p -> d() );
p -> setc( t -> ch[ ! d ] , d );
t -> setc( p , ! d );
p -> upd();
if( p == root ) root = t;
}
 
void splay( Node* t , Node* f = null ) {
for( Node* p = t -> p ; p != f ; p = t -> p ) {
if( p -> p != f )
   t -> d() != p -> d() ? rot( t ) : rot( p );
rot( t );
}
t -> upd();
}
 
Node* select( int k ) {
for( Node* t = root ; ; ) {
t -> relax();
int s = t -> ch[ 0 ] -> s;
if( k == s ) return t;
if( k > s )
   k -= s + 1 , t = t -> ch[ 1 ];
else 
   t = t -> ch[ 0 ];
}
}
 
Node* get( int l , int r ) {
l-- , r++;
Node* L = select( l );
Node* R = select( r );
splay( L );
splay( R , L );
return R -> ch[ 0 ];
}
void init() {
pt = NODE;
null = new( Node );
null -> s = 0;
}
 
int main() {
freopen( "test.in" , "r" , stdin );
init();
int n , m;
cin >> n >> m;
Rep( i , n ) scanf( "%d" , seq + i );
seq[ 0 ] = seq[ n + 1 ] = 0;
root = build( 0 , n + 2 );
char s[ 10 ];
int x , t;
while( m-- ) {
scanf( " %s%d" , s , &x );
if( s[ 0 ] == 'Q' ) {
Node* t = select( x );
printf( "%d\n" , t -> v );
splay( t );
} else if( s[ 0 ] == 'A' ) {
Node* t = V[ x ];
splay( t );
printf( "%d\n" , t -> ch[ 0 ] -> s - 1 );
} else if( s[ 0 ] == 'B' ) {
Node* t = V[ x ];
splay( t );
int s = t -> ch[ 0 ] -> s;
get( s , n ) -> Rev();
get( s , n - 1 ) -> Rev();
} else if( s[ 0 ] == 'T' ) {
Node* t = V[ x ];
splay( t );
int s = t -> ch[ 0 ] -> s;
get( 1 , s ) -> Rev();
get( 2 , s ) -> Rev();
} else {
int a;
scanf( "%d" , &a );
Node* t = V[ x ];
splay( t );
int s = t -> ch[ 0 ] -> s;
int l = s , r = s + a;
if( l == r ) continue;
if( l > r ) swap( l , r );
get( l , r ) -> Rev();
}
}
return 0;
}

 

---------------------------------------------------------------------------------------------

1861: [Zjoi2006]Book 书架

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 760  Solved: 437
[Submit][Status][Discuss]

Description

小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。 久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。

Input

第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式: 1. Top S——表示把编号为S的书房在最上面。 2. Bottom S——表示把编号为S的书房在最下面。 3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书; 4. Ask S——询问编号为S的书的上面目前有多少本书。 5. Query S——询问从上面数起的第S本书的编号。

Output

对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。

Sample Input

10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2

Sample Output

2
9
9
7
5
3

HINT

数据范围


100%的数据,n,m < = 80000

 

Source

 

posted @ 2015-06-20 17:12  JSZX11556  阅读(275)  评论(0编辑  收藏  举报