其实就是带修改的区间第K大。
写了一下BIT套主席树,内存飞起,似乎需要特别的优化技巧 = = 所以还是写了一下线段树套平衡树,跑了1s左右。
其实线段树套平衡树就是归并树的自然扩展而已。
归并树是把归并排序的过程建成一颗线段树,每个节点是一个数组,存的是这个节点对应区间的元素的正序:
空间复杂度O( n log n ) 。
每次查询的时候二分答案, 问题转化成询问区间中有多少个数比k小。外层查询和一般的线段树一样,只是在线段树的节点处需要再次二分得到节点区间中比k小的数的个数。这样二分答案有一个log ,线段树中询问也需要一个log ,线段树节点处二分需要一个log ,每次询问的复杂度为O( log^3 n ) 。
加入修改操作的时候,只需要把线段树节点的数组改为平衡树实现就好了。这是很自然的,线段树节点维护对应节点的顺序,又要支持修改,显然平衡树符合要求。
平衡树用splay实现了一下跑了1080ms ,然后用Treap实现了一下RE得浑身难受。。。实在是码力不行啊Orz
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std ; 5 const int N = 50000 +10 ,INF = ~1u>>1; 6 int M ,num[N] ; 7 struct node{ 8 node *ch[2] ,*p ; 9 int size ,val ; 10 bool d() ; 11 void setc( node * ,bool ) ,rol() ,pushup() ; 12 }pool[N*19] ,*cur ,NU ,*null = &NU ; 13 bool node::d(){ 14 return p->ch[1] == this ; 15 } 16 void node::setc( node *c ,bool d ){ 17 ch[d] = c ,c->p = this ; 18 } 19 void node::rol(){ 20 node *s = p ; 21 int dd = d() ; 22 s->p->setc( this ,p->d() ) ; 23 s->setc( ch[!dd] ,dd ) ; 24 setc( s ,!dd ) ; 25 s->pushup() ; 26 } 27 void node::pushup(){ 28 size = ch[0]->size + ch[1]->size + 1 ; 29 } 30 struct Splay{ 31 node *root ; 32 void splay( node * ,node * ) ,insert( node * ) ; 33 void change( int ,int ) ,find( int ) ,init() ; 34 node *get( int ) ; 35 int rank( int ) ; 36 }tree[N<<2] ; 37 38 node *newnode( int val ){ 39 cur->val = val ; 40 cur->size = 1 ; 41 cur->ch[0] = cur->ch[1] = cur->p = null ; 42 return cur ++ ; 43 } 44 void Splay::init(){ 45 root = newnode(-INF) ; 46 } 47 void Splay::splay( node *x ,node *p = null ){ 48 while( x->p != p ){ 49 if( x->p->p != p ) 50 x->d() == x->p->d() ? x->p->rol() : x->rol() ; 51 x->rol() ; 52 } 53 x->pushup() ; 54 if( p == null ) root = x ; 55 } 56 void Splay::insert( node *x ){ 57 if( root == null ) root = x ,root->p = null ; 58 else for( node *t = root ;; ){ 59 ++t->size ; 60 node *&s = t->ch[ x->val > t->val ] ; 61 if( s == null ){ 62 s = x ,s->p = t ; 63 splay( x ) ; 64 break ; 65 } 66 t = s ; 67 } 68 } 69 void Splay::find( int x ){ 70 for( node *t = root ;; ){ 71 if( x == t->val ){ 72 splay( t ) ; 73 return ; 74 } 75 t = t->ch[ x > t->val ] ; 76 } 77 } 78 void Splay::change( int x ,int val ){ 79 find( x ) ; 80 node *p = root ; 81 node *t = get( root->ch[0]->size ) ; 82 splay( t ,root ) ; 83 t->setc( root->ch[1] ,1 ) ; 84 t->pushup() ,root = t ,t->p = null ; 85 p->val = val ,p->size = 1 ; 86 p->ch[0] = p->ch[1] = null ; 87 insert( p ) ; 88 return ; 89 } 90 node *Splay::get( int s ){ 91 for( node *t = root ;; ){ 92 int k = t->ch[0]->size ; 93 if( s == k + 1 ) return t ; 94 if( s > k + 1 ) s -= k + 1 ,t = t->ch[1] ; 95 else t = t->ch[0] ; 96 } 97 } 98 int Splay::rank( int x ){ 99 int res = 0 ; 100 for( node *t = root ;; ){ 101 node *&s = t->ch[ x > t->val ] ; 102 if( t->val < x ) res += t->ch[0]->size + 1 ; 103 if( s == null ){ 104 splay(t) ; 105 return res - 1 ; 106 } 107 t = s ; 108 } 109 } 110 void setIt( int p ,int k ,int s = M ,int x = 1 ){ 111 tree[x].insert( newnode(k) ) ; 112 if( s == 1 ) return ; 113 if( p <= s/2 ) setIt( p ,k ,s/2 ,x<<1 ) ; 114 else setIt( p - s/2 ,k ,s - s/2 ,x<<1|1 ) ; 115 } 116 void change( int p ,int u ,int v ,int s = M ,int x = 1 ){ 117 tree[x].change( u ,v ) ; 118 if( s == 1 ) return ; 119 if( p <= s/2 ) change( p ,u ,v ,s/2 ,x<<1 ) ; 120 else change( p-s/2 ,u ,v ,s-s/2 ,x<<1|1 ) ; 121 } 122 int Q ; 123 void query( int l ,int r ,int ans ,int s = M ,int x = 1 ){ 124 if( l <= 1 && r >= s ){ 125 Q += tree[x].rank(ans) ; 126 return ; 127 } 128 if( l <= s/2 ) query( l ,r ,ans ,s/2 ,x<<1 ) ; 129 if( r > s/2 ) query( l-s/2 ,r-s/2 ,ans ,s-s/2 ,x<<1|1 ) ; 130 } 131 bool judge( int l ,int r ,int ans ,int kth ){ 132 Q = 0 ; 133 query( l ,r ,ans ) ; 134 if( Q <= kth - 1 ) return 1; 135 return 0 ; 136 } 137 void init(){ 138 cur = pool ; 139 } 140 void build( int x = 1 ,int s = M ){ 141 tree[x].init() ; 142 if( s == 1 ) return ; 143 build( x<<1 ,s/2 ) ; 144 build( x<<1|1 ,s-s/2 ) ; 145 } 146 int main(){ 147 int n ,m ,x ,s ,t ,u ; 148 int T ; 149 scanf( "%d" ,&T ) ; 150 while( T -- ){ 151 scanf("%d %d" ,&n ,&m ) ; 152 M = n ; 153 init() ; 154 int minn = 0 ,maxn = 0 ; 155 build(); 156 for( int i = 1 ;i <= n ;i ++ ){ 157 scanf( "%d" ,&x ) ; 158 num[i] = x ; 159 setIt( i ,x ) ; 160 minn = min ( minn ,x ) ; 161 maxn = max ( maxn ,x ) ; 162 } 163 char o[2]; 164 while( m -- ){ 165 scanf( "%s" ,&o ) ; 166 if( o[0] == 'C' ){ 167 scanf( "%d %d" ,&s ,&t ) ; 168 minn = min( minn ,t ) ; 169 maxn = max( maxn ,t ) ; 170 change( s ,num[s] ,t ) ; 171 num[s] = t ; 172 continue ; 173 } 174 scanf( "%d %d %d" ,&s ,&t ,&u ) ; 175 int l = minn ,r = maxn ; 176 while( l < r ){ 177 int mid = ( l + r >> 1 ) + 1 ; 178 if( judge( s ,t ,mid ,u ) ) l = mid ; 179 else r = mid - 1 ; 180 } 181 printf( "%d\n" ,l ) ; 182 } 183 } 184 }