标签:
题目连接:zoj2112
给出n个点,两种操作,Q:询问在[l,r]内的第k大的数,C:更改第i个数位x
动态的询问第k大,使用树状数组修改和查询前缀和。
因为给出的空间小,所以可以将n个点做成一个静态的主席树,然后对于修改的值,在另一个主席树中修改,查询时同时查询这两个主席树就可以了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:1024000000,1024000000")
struct node{
int l , r , num ;
}p[2500000];//所有的节点,p[i].l第i个节点的左儿子的下标,p[i].num第i个节点有的点数
int n , q , cnt ;
int a[50010] , b[10010][3] ;//a为初始的输入,b为操作数
int s[60010] , m ;//离散化的数组,和离散后的个数m
int tree[50010] , S[50010];//tree动态的主席树,使用树状数组修改/查询前缀和,S静态的主席树,保留初始的n个点的前缀和。
int use[50010] ;
int lowbit(int x) {
return x & -x ;
}
int build(int l,int r) {
int x = cnt++ , mid = (l+r)/2 ;
p[x].num = 0 ;
if( l < r ) {
p[x].l = build(l,mid) ;
p[x].r = build(mid+1,r) ;
}
return x ;
}
int search1(int x) {
int low = 0 , mid , high = m-1 ;
while( low <= high ) {
mid = (low + high)/2 ;
if( s[mid] == x ) return mid ;
else if( s[mid] < x ) low = mid + 1 ;
else high = mid - 1 ;
}
}
int update(int y,int k,int num) {
int root = cnt++ , x = root ;
int l = 0 , r = m-1 , mid ;
p[x].num = p[y].num + num ;
while( l < r ) {
mid = (l+r)/2 ;
if( k <= mid ) {
r = mid ;
p[x].l = cnt++ ;
p[x].r = p[y].r ;
x = p[x].l ;
y = p[y].l ;
}
else {
l = mid + 1 ;
p[x].l = p[y].l ;
p[x].r = cnt++ ;
x = p[x].r ;
y = p[y].r ;
}
p[x].num = p[y].num + num ;
}
return root ;
}
void init() {
int k , i , j ;
sort(s,s+m) ;
m = unique(s,s+m)-s ;
cnt = 0 ;
S[0] = build(0,m-1) ;
for(i = 1 ; i <= n ; i++)
S[i] = update(S[i-1],search1(a[i]),1) ;
for(i = 1 ; i <= n ; i++)
tree[i] = S[0] ;
}
int sum(int i) {
int sum = 0 ;
while( i ) {
sum += p[ p[ use[i] ].l ].num ;
i -= lowbit(i) ;
}
return sum ;
}
void query(int ll,int rr,int k) {
int num , i , l = 0 , r = m-1 , mid , rt_l = S[ll-1] , rt_r = S[rr] ;
for(i = ll-1 ; i ; i -= lowbit(i)) use[i] = tree[i] ;
for(i = rr ; i ; i -= lowbit(i)) use[i] = tree[i] ;
while( l < r ) {
num = sum(rr) - sum(ll-1) + p[ p[rt_r].l ].num - p[ p[rt_l].l ].num ;
mid = (l + r ) / 2 ;
if( num >= k ) {
r = mid ;
for(i = ll-1 ; i ; i -= lowbit(i))
use[i] = p[ use[i] ].l ;
for(i = rr ; i ; i -= lowbit(i))
use[i] = p[ use[i] ].l ;
rt_l = p[ rt_l ].l ;
rt_r = p[ rt_r ].l ;
}
else {
l = mid + 1 ;
k -= num ;
for(i = ll-1 ; i ; i -= lowbit(i))
use[i] = p[ use[i] ].r ;
for(i = rr ; i ; i -= lowbit(i))
use[i] = p[ use[i] ].r ;
rt_l = p[ rt_l ].r ;
rt_r = p[ rt_r ].r ;
}
}
printf("%d\n", s[l]) ;
}
int main() {
int t , i , j , k1 , k2 ;
int l , r ;
char str[10] ;
scanf("%d", &t) ;
while( t-- ) {
scanf("%d %d", &n, &q) ;
m = 0 ;
for(i = 1 ; i <= n ; i++) {
scanf("%d", &a[i]) ;
s[m++] = a[i] ;
}
for(i = 0 ; i < q ; i++) {
scanf("%s", str) ;
if( str[0] == 'Q' ) {
scanf("%d %d %d", &b[i][0], &b[i][1], &b[i][2]) ;
}
else {
b[i][0] = -1 ;
scanf("%d %d", &b[i][1], &b[i][2]) ;
s[m++] = b[i][2] ;
}
}
init() ;
for(i = 0 ; i < q ; i++) {
if( b[i][0] == -1 ) {
k1 = search1( a[ b[i][1] ] ) ;
k2 = search1( b[i][2] ) ;
for(j = b[i][1] ; j <= n ; j += lowbit(j)) {
tree[j] = update(tree[j],k1,-1) ;
tree[j] = update(tree[j],k2,1) ;
}
a[ b[i][1] ] = b[i][2] ;
}
else {
query(b[i][0],b[i][1],b[i][2]) ;
}
}
}
return 0 ;
}
zoj2112--Dynamic Rankings(树状数组+主席树)
标签:
原文地址:http://blog.csdn.net/winddreams/article/details/45316491