题目连接: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 ; }