【ZOJ】2112 Dynamic Rankings 动态第K大【线段树套treap】

来源:互联网 发布:标准文摘数据库 编辑:程序博客网 时间:2024/04/30 15:59

传送门:【ZOJ】2112 Dynamic Rankings


题目分析:这题我用的线段树套treap。

首先我们让每个线段树的节点都是一棵treap,先将初始的元素插入到途径的所有区间的treap中,易知这样子我们用掉了nlogn的空间(每个元素都需要经过logn的线段树的节点)。然后对于每一次修改,我们只需要将treap中原来的值删除,然后插入新的值即可,这样我们用掉了mlogn的空间。但是对于查询区间第K大,由于一段查询区间是由多个线段树节点构成,所以我们不能直接得到第K大,但是我们可以退而求其次,每次二分一个数,查询所有区间内不大于这个数的个数cnt,如果cnt<=K,那么调整上界,否则调整下界,用二分可以找到这么一个数x,使x满足num{x-1}<k,num{x}>=k,这样我们得到的x其实就是第k大。

整个算法使用静态模拟指针,动态分配内存会超内存,空间复杂度O((n+m)logn),时间复杂度O(mlog^3n)。


代码如下:


#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>using namespace std ;#define REP( i , a , b ) for ( int i = a ; i < b ; ++ i )#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define REV( i , a , b ) for ( int i = a ; i >= b ; -- i )#define CLR( a , x ) memset ( a , x , sizeof a )#define lson ( o << 1 ) , l , m#define rson ( o << 1 | 1 ) , m + 1 , r#define mid ( ( l + r ) >> 1 )const int MAXN = 50005 ;struct Node {Node *ch[2] ;int r , v , s ;int cmp ( int x ) {return x == v ? -1 : ( x < v ? 0 : 1 ) ;}void maintain () {s = 1 ;if ( ch[0] != NULL ) s += ch[0] -> s ;if ( ch[1] != NULL ) s += ch[1] -> s ;}} node[900000] , *top , *root[MAXN << 2] ;int a[MAXN] ;int n ;Node *newnode ( int x ) {top -> v = x ;top -> s = 1 ;top -> r = rand () ;top -> ch[0] = top -> ch[1] = NULL ;return top ++ ;}void rotate ( Node *&o , int d ) {Node *k = o -> ch[d ^ 1] ;o -> ch[d ^ 1] = k -> ch[d] ;k -> ch[d] = o ;o -> maintain () ;k -> maintain () ;o = k ;}void insert ( Node *&o , int x ) {if ( o == NULL ) o = newnode ( x ) ;else {int d = x < o -> v ? 0 : 1 ;insert ( o -> ch[d] , x ) ;if ( o -> ch[d] -> r > o -> r ) rotate ( o , d ^ 1 ) ;}o -> maintain () ;}void remove ( Node *&o , int x ) {int d = o -> cmp ( x ) ;if ( d == -1 ) {if ( o -> ch[0] != NULL && o -> ch[1] != NULL ) {int d2 = o -> ch[0] -> r > o -> ch[1] -> r ? 1 : 0 ;rotate ( o , d2 ) ;remove ( o -> ch[d2] , x ) ;} else {o = o -> ch[0] != NULL ? o -> ch[0] : o -> ch[1] ;}} else {remove ( o -> ch[d] , x ) ;}if ( o != NULL ) o -> maintain () ;}int kth ( Node *o , int k ) {while ( o != NULL ) {int s = o -> ch[0] != NULL ? o -> ch[0] -> s : 0 ;if ( s + 1 == k ) return o -> v ;if ( k <= s ) o = o -> ch[0] ;else {o = o -> ch[1] ;k -= s + 1 ;}}return 0 ;}void update ( int pre , int now , int x , int o , int l , int r ) {if ( pre ) remove ( root[o] , pre ) ;insert ( root[o] , now ) ;if ( l == r ) return ;int m = mid ;if ( x <= m ) update ( pre , now , x , lson ) ;else          update ( pre , now , x , rson ) ;}int getnum ( Node *o , int x ) {int cnt = 0 ;while ( o != NULL ) {int d = x < o -> v ? 0 : 1 ;if ( d == 0 ) o = o -> ch[0] ;else {cnt += 1 + ( o -> ch[0] != NULL ? o -> ch[0] -> s : 0 ) ;o = o -> ch[1] ;}}return cnt ;}int query ( int x , int L , int R , int o , int l , int r ) {if ( L <= l && r <= R ) return getnum ( root[o] , x ) ;int m = mid ;if ( R <= m ) return query ( x , L , R , lson ) ;if ( m <  L ) return query ( x , L , R , rson ) ;return query ( x , L , R , lson ) + query ( x , L , R , rson ) ;}int search ( int L , int R , int k ) {int l = 0 , r = 1e9 + 7 ;while ( l < r ) {int m = mid ;if ( query ( m , L , R , 1 , 1 , n ) >= k ) r = m ;else l = m + 1 ;}return l ;}void init () {memset ( root , 0 , sizeof root ) ;top = node ;}void solve () {int m ;int l , r , k ;int x , v ;char type ;init () ;scanf ( "%d%d" , &n , &m ) ;FOR ( i , 1 , n ) {scanf ( "%d" , &a[i] ) ;update ( 0 , a[i] , i , 1 , 1 , n ) ;}REP ( i , 0 , m ) {scanf ( " %c" , &type ) ;if ( type == 'Q' ) {scanf ( "%d%d%d" , &l , &r , &k ) ;printf ( "%d\n" , search ( l , r , k ) ) ;} else {scanf ( "%d%d" , &x , &v ) ;update ( a[x] , v , x , 1 , 1 , n ) ;a[x] = v ;}}}int main () {int T ;scanf ( "%d" , &T ) ;while ( T -- )solve () ;return 0 ;}


0 0
原创粉丝点击