问题: 给定一个长N<=50000的序列,允许有两种操作: ①询问第l至第r个之间的第k大的数? ②将位置i的数改为y。
分析:若是不需要修改可采用划分树做。线段树或splay可以查找第k大数,而区间[l , r]之间只需处理前缀和即可,但朴素实现的前缀和修改复杂的需要O(n),若采用树状数组只需O(logn) , 故只需用树状数组套主席树即可。不过ZOJ这题内存卡得很紧,直接在数组数组上插入原始序列需要O(n*logn*logn)空间复杂的肯定MLE , 但是修改操作却相对较少,我们可以将他们分开操作 , 用一个类似前缀数组记录原始序列的前缀和 , 而用数装数组处理后面的操作 。 空间只需O(n*logn + m*logn*logn) 。
还有其他做法,像线段树套splay : http://www.cnblogs.com/staginner/archive/2012/03/22/2411993.html
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL ;
const int null = 0 ;
const int maxn = 60010 ;
const int maxm = 1800000 ;
int n , m ;
int value[maxn] ,val[maxn], N ;
struct Oper{
char cmd ;
int l , r , k ;
Oper(){} ;
Oper(char cmd , int l ,int r , int k): cmd(cmd) , l(l) , r(r) , k(k){} ;
}q[10010]; int qn ;
int tree[maxn] ,S[maxn], te[maxn] , lson[maxm] , rson[maxm] , size[maxm] ,tot;
void init(){
tot = 0 ;
size[null]=lson[null] = rson[null]= 0 ;
for(int i=0; i<=n; i++) tree[i] = null ;
S[0] = 0 ;
}
inline int lowbit(int x) {
return x & -x ;
}
void insert(int pre , int &o, int L ,int R ,int x ,int val){
int mid= (L+R)>>1 ;
o = ++ tot;
lson[o] = lson[pre] ;
rson[o] = rson[pre] ;
size[o] = size[pre] + val ;
if(L==R)return ;
if(x <= mid) insert(lson[pre] , lson[o] , L , mid , x , val) ;
else insert(rson[pre] , rson[o] , mid+1 , R , x , val) ;
}
void add(int pos ,int x, int val) {
for(int i=pos; i<=n; i+=lowbit(i)) {
insert(tree[i] , tree[i] , 1 , N , x , val) ;
}
}
int sum_lson(int x) {
int ret = 0 ;
for(int i=x; i; i-=lowbit(i)) {
ret += size[lson[te[i]]] ;
}
return ret ;
}
int query(int l , int r, int sl, int sr , int k) {
for(int i=l; i; i-=lowbit(i)) te[i] = tree[i] ;
for(int i=r; i; i-=lowbit(i)) te[i] = tree[i] ;
int L = 1 , R = N ;
while(L < R){
int mid =(L+R)>>1 ;
int sz = sum_lson(r) - sum_lson(l) + size[lson[sr]] - size[lson[sl]] ;
if( k<= sz) {
R = mid ;
sl = lson[sl] , sr = lson[sr] ;
for(int i=l; i; i-=lowbit(i)) te[i] = lson[te[i]] ;
for(int i=r; i; i-=lowbit(i)) te[i] = lson[te[i]] ;
}
else {
L = mid + 1 ;
k -= sz ;
sl = rson[sl] , sr= rson[sr] ;
for(int i=l; i; i-=lowbit(i)) te[i] = rson[te[i]] ;
for(int i=r; i; i-=lowbit(i)) te[i] = rson[te[i]] ;
}
}
return value[L-1] ;
}
int main()
{
// freopen("in.txt", "r" ,stdin) ;
int T ;
scanf("%d" , &T) ;
while(T--) {
scanf("%d%d" ,&n ,&m) ;
init() ;
N = 0 ;
for(int i=0; i<n; i++) {
scanf("%d" , &val[i]) ;
value[N++] = val[i] ;
}
qn = 0;
for(int i=0; i<m; i++) {
char str[5] ;
scanf("%s" , str) ;
int l ,r ,k;
if(str[0] == 'Q') {
scanf("%d%d%d" , &l , &r , &k) ;
q[qn++] = Oper(str[0] , l , r ,k) ;
}
else {
scanf("%d%d" ,&l , &r);
q[qn++] = Oper(str[0] , l , r , 0) ;
value[N++] = q[qn-1].r ;
}
}
sort(value , value+N);
N = unique(value , value+N) - value ;
for(int i=0; i<n; i++) val[i] = lower_bound(value , value+N , val[i]) - value + 1;
for(int i=0; i<qn; i++) if(q[i].cmd == 'C') {
q[i].r = lower_bound(value , value+N , q[i].r) - value + 1 ;
}
for(int i=0; i<n; i++) {
//add(i+1 , val[i] , 1) ;
insert(S[i] , S[i+1] , 1 ,N , val[i] , 1) ;
}
for(int i=0; i<qn; i++) {
if(q[i].cmd == 'Q') {
int ans = query(q[i].l-1 , q[i].r ,S[q[i].l-1] , S[q[i].r], q[i].k) ;
printf("%d\n" , ans);
}
else {
add(q[i].l , val[q[i].l - 1] , -1) ;
add(q[i].l , q[i].r , 1) ;
val[q[i].l- 1] = q[i].r ;
}
}
// printf("tot = %d\n" , tot) ;
}
return 0;
}