zoj 2112 块状链表 OR 线段树套treap 求动态第k大

块链:块内排序方便二分,然后进行类似于冒泡排序的更新即可。

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 #include <cmath>
  6 using namespace std;
  7 
  8 const int INF = 1000000000;
  9 const int N = 50000;
 10 const int M = 400;
 11 int a[N];
 12 int b[M][M];
 13 int n, m, ps, num;
 14 
 15 void update( int pos, int val )
 16 {
 17     int cur = pos / ps;
 18     if ( cur < num - 1 )
 19     {
 20         int p = lower_bound( b[cur], b[cur] + ps, a[pos] ) - b[cur];
 21         if ( val > a[pos] )
 22         {
 23             while ( p + 1 < ps && b[cur][p + 1] < val ) 
 24             {
 25                 b[cur][p] = b[cur][p + 1];
 26                 p++;
 27             }
 28         }
 29         else
 30         {
 31             while ( p - 1 >= 0 && b[cur][p - 1] > val )
 32             {
 33                 b[cur][p] = b[cur][p - 1];
 34                 p--;
 35             }
 36         }
 37         b[cur][p] = val;
 38     }
 39     a[pos] = val;
 40 }
 41 
 42 int query( int l, int r, int k )
 43 {
 44     int cur = l / ps, ncur = r / ps;
 45     int lb = 0, ub = INF;
 46     while ( lb < ub )
 47     {
 48         int mid = ( lb + ub ) >> 1;
 49         int cnt = 0;
 50         if ( cur != ncur )
 51         {
 52             for ( int i = cur + 1; i <= ncur - 1; i++ )
 53             {
 54                 cnt += upper_bound( b[i], b[i] + ps, mid ) - b[i];
 55             }
 56             for ( int i = l; i < ( cur + 1 ) * ps; i++ )
 57             {
 58                 if ( a[i] <= mid ) cnt++;
 59             }
 60             for ( int i = ncur * ps; i <= r; i++ )
 61             {
 62                 if ( a[i] <= mid ) cnt++;
 63             }
 64         }
 65         else
 66         {
 67             for ( int i = l; i <= r; i++ )
 68             {
 69                 if ( a[i] <= mid ) cnt++;
 70             } 
 71         }
 72         if ( cnt >= k )
 73         {
 74             ub = mid;
 75         }
 76         else
 77         {
 78             lb = mid + 1;
 79         }
 80     }
 81     return ub;
 82 }
 83 
 84 int main ()
 85 {
 86     int t;
 87     scanf("%d", &t);
 88     while ( t-- )
 89     {
 90         scanf("%d%d", &n, &m);
 91         ps = 400;
 92         for ( int i = 0; i < n; i++ )
 93         {
 94             scanf("%d", a + i);
 95             b[i / ps][i % ps] = a[i];
 96         }
 97         num = ( n + ps - 1 ) / ps;
 98         for ( int i = 0; i < num - 1; i++ )
 99         {
100             sort( b[i], b[i] + ps );
101         }
102         while ( m-- )
103         {
104             char op[2];
105             int x, y, k;
106             scanf("%s", op);
107             if ( op[0] == 'Q' )
108             {
109                 scanf("%d%d%d", &x, &y, &k);
110                 x--, y--;
111                 printf("%d\n", query( x, y, k ));
112             }
113             else
114             {
115                 scanf("%d%d", &x, &y);
116                 x--;
117                 update( x, y );
118             }
119         }
120     }
121     return 0;
122 }

线段树套treap:线段树上的每个结点维护一个treap,里面有该区间的元素,查询时二分答案。

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 using namespace std;
  6 
  7 const int INF = 1000000000;
  8 const int N = 100001;
  9 int a[N];
 10 int n, m;
 11 
 12 struct Node 
 13 {
 14     Node * ch[2];
 15     int v, r, size, cnt;
 16     int cmp( int x )
 17     {
 18         if ( x == v ) return -1;
 19         return x < v ? 0 : 1;
 20     }    
 21     void maintain()
 22     {
 23         size = cnt;
 24         if ( ch[0] != NULL ) size += ch[0]->size;
 25         if ( ch[1] != NULL ) size += ch[1]->size;
 26     }
 27 };
 28 
 29 void rotate( Node * & o, int d )
 30 {
 31     Node * k = o->ch[d ^ 1];
 32     o->ch[d ^ 1] = k->ch[d];
 33     k->ch[d] = o;
 34     o->maintain();
 35     k->maintain();
 36     o = k;
 37 }
 38 
 39 int ran()
 40 {
 41     static int x = 1364684679;
 42     x += ( ( x << 2 ) | 1 );
 43     return x;
 44 }
 45 
 46 void insert( Node * & o, int x )
 47 {
 48     if ( o == NULL )
 49     {
 50         o = new Node();
 51         o->ch[0] = o->ch[1] = NULL;
 52         o->v = x;
 53         o->r = ran();
 54         o->size = o->cnt = 1;
 55     }
 56     else
 57     {
 58         int d = o->cmp(x);
 59         if ( d == -1 )
 60         {
 61             o->cnt++;
 62             o->size++;
 63         }
 64         else
 65         {
 66             insert( o->ch[d], x );
 67             if ( o->ch[d]->r > o->r )
 68             {
 69                 rotate( o, d ^ 1 );
 70             }
 71             else
 72             {
 73                 o->maintain();
 74             }
 75         }
 76     }
 77 }
 78 
 79 void remove( Node * & o, int x )
 80 {
 81     int d = o->cmp(x);
 82     if ( d == -1 )
 83     {
 84         if ( o->cnt > 1 )
 85         {
 86             o->cnt--;
 87             o->size--;
 88         }
 89         else
 90         {
 91             if ( o->ch[0] != NULL && o->ch[1] != NULL )
 92             {
 93                 int dd = ( o->ch[0]->r > o->ch[1]->r ? 1 : 0 );
 94                 rotate( o, dd );
 95                 remove( o->ch[dd], x );
 96             }
 97             else
 98             {
 99                 Node * u = o;
100                 if ( o->ch[0] == NULL ) o = o->ch[1];
101                 else o = o->ch[0];
102                 delete u;
103             }
104             if ( o != NULL ) o->maintain();
105         }
106     }
107     else
108     {
109         remove( o->ch[d], x );
110         o->maintain();
111     }
112 }
113 
114 int ranker( Node * o, int x, int sum )
115 {
116     if ( o == NULL ) return sum;
117     int d = o->cmp(x);
118     if ( d == -1 )
119     {
120         return sum + ( o->ch[0] == NULL ? 0 : o->ch[0]->size ) + o->cnt;
121     }
122     else if ( d == 0 )    
123     {
124         return ranker( o->ch[0], x, sum );
125     }
126     else
127     {
128         int tmp = ( o->ch[0] == NULL ? 0 : o->ch[0]->size );
129         return ranker( o->ch[1], x, sum + tmp + o->cnt );
130     }
131 }
132 
133 struct S
134 {
135     int l, r;
136     Node * rt;
137 } s[N << 2];
138 
139 Node * build_treap( int l, int r )
140 {
141     Node * o = NULL;
142     for ( int i = l; i <= r; i++ )
143     {
144         insert( o, a[i] );
145     }
146     return o;
147 }
148 
149 void build( int i, int l, int r )
150 {
151     s[i].l = l, s[i].r = r;
152     s[i].rt = build_treap( l, r );
153     if ( l == r ) return ;
154     int mid = ( l + r ) >> 1;
155     build( i << 1, l, mid );
156     build( i << 1 | 1, mid + 1, r );
157 }
158 
159 void update( int i, int pos, int val )
160 {
161     if ( s[i].l == pos && s[i].r == pos )
162     {
163         s[i].rt->v = val;
164         return ;
165     }
166     remove( s[i].rt, a[pos] );
167     insert( s[i].rt, val );
168     int mid = ( s[i].l + s[i].r ) >> 1;
169     if ( pos <= mid )
170     {
171         update( i << 1, pos, val );
172     }
173     else
174     {
175         update( i << 1 | 1, pos, val );
176     }
177 }
178 
179 int query( int i, int l, int r, int val )
180 {
181     if ( s[i].l == l && s[i].r == r )
182     {
183         return ranker( s[i].rt, val, 0 );
184     }
185     int mid = ( s[i].l + s[i].r ) >> 1;
186     if ( r <= mid )
187     {
188         return query( i << 1, l, r, val );
189     }
190     else if ( l > mid )
191     {
192         return query( i << 1 | 1, l, r, val );
193     }
194     else
195     {
196         return query( i << 1, l, mid, val ) + query( i << 1 | 1, mid + 1, r, val );
197     }
198 }
199 
200 int kth( int l, int r, int k )
201 {
202     int lb = 1, ub = INF;
203     while ( lb < ub )
204     {
205         int mid = ( lb + ub ) >> 1;
206         int nn = query( 1, l, r, mid );
207         if ( nn >= k )
208         {
209             ub = mid;
210         }
211         else
212         {
213             lb = mid + 1;
214         }
215     }
216     return lb;
217 }
218 
219 void clear( Node * o )
220 {
221     if ( o == NULL ) return ;
222     clear( o->ch[0] );
223     clear( o->ch[1] );
224     delete o;
225 }
226 
227 void del( int i )
228 {
229     if ( s[i].l == s[i].r )
230     {
231         delete s[i].rt;
232         return ;
233     }
234     del( i << 1 );
235     del( i << 1 | 1 );
236     clear( s[i].rt );
237 }
238 
239 int main ()
240 {
241     while ( scanf("%d", &n) != EOF )
242     {
243         for ( int i = 1; i <= n; i++ )
244         {
245             scanf("%d", &a[i]);
246         }
247         build( 1, 1, n );
248         scanf("%d", &m);
249         while ( m-- )
250         {
251             int op, x, y, k;
252             scanf("%d", &op);
253             if ( op == 1 )
254             {
255                 scanf("%d%d", &x, &y);
256                 update( 1, x, y );
257                 a[x] = y;
258             }
259             else
260             {
261                 scanf("%d%d%d", &x, &y, &k);
262                 printf("%d\n", kth( x, y, k ));
263             }
264         }
265         del(1);
266     }
267     return 0;
268 }

 

转载于:https://www.cnblogs.com/huoxiayu/p/4746139.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值