BZOJ1901 - Dynamic Rankings(树状数组套主席树)

题目大意

给定一个有N个数字的序列,然后又m个指令,指令种类只有两种,形式如下:

Q l r k 要求你查询区间[l,r]第k小的数是哪个

C i t  要求你把第i个数修改为t

题解

动态的区间第k小,如果还是按照静态的主席树做的话,每次修改需要对n个线段树进行修改,这样显然会TLE,所以我们需要用树状数组,这样每次只需要对logn颗线段树修改即可,修改的时间复杂度为logn^2,询问的时间复杂度为logn^2,空间复杂度为nlogn^2

还有一种空间复杂度为nlogn+mlogn^2的方法,就是先建立n颗静态的主席树,空间复杂度为nlogn,然后再更新的时候用树状数组套线段树,这样空间复杂度为mlogn^2,所以总空间复杂度为nlogn+mlogn^2

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 140000
#define NN 10005
#define lson l,m,ls[s]
#define rson m+1,r,rs[s]
int ls[20*MAXN],rs[20*MAXN],cnt[20*MAXN];
int T[MAXN],tot;
int len,n,m;
int num[MAXN];
char op[10010][3];
int a[NN*2],lt[NN],rt[NN],K[NN];
int L[30],R[30];
int N,M;
void build(int l,int r,int &s)
{
    s=++tot;
    cnt[s]=0;
    if(l==r) return;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int last,int p,int l,int r,int &s,int d)
{
    s=++tot;
    ls[s]=ls[last],rs[s]=rs[last],cnt[s]=cnt[last]+d;
    if(l==r) return;
    int m=(l+r)>>1;
    if(p<=m) update(ls[last],p,lson,d);
    else     update(rs[last],p,rson,d);

}
int query(int l,int r,int k)
{
    if(l==r) return r;
    int suma=0,sumb=0;
    for(int i=1; i<=N; i++) suma+=cnt[ls[L[i]]];
    for(int i=1; i<=M; i++) sumb+=cnt[ls[R[i]]];
    int m=(l+r)>>1,sum=sumb-suma;
    if(sum>=k)
    {
        for(int i=1; i<=N; i++) L[i]=ls[L[i]];
        for(int i=1; i<=M; i++) R[i]=ls[R[i]];
        return query(l,m,k);
    }
    else
    {
        for(int i=1; i<=N; i++) L[i]=rs[L[i]];
        for(int i=1; i<=M; i++) R[i]=rs[R[i]];
        return query(m+1,r,k-sum);
    }
}
int lowbit(int x)
{
    return x&-x;
}
void BIT(int x,int value,int d)
{
    while(x<=n)
    {
        update(T[x],value,1,len,T[x],d);
        x+=lowbit(x);
    }
}
int BIT_query(int l,int r,int k)
{
    N=0,M=0;
    while(l>0)
    {
        L[++N]=T[l];
        l-=lowbit(l);
    }
    while(r>0)
    {
        R[++M]=T[r];
        r-=lowbit(r);
    }
    return query(1,len,k);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&num[i]);
        a[++len]=num[i];
    }
    for(int i=1; i<=m; i++)
    {
        scanf("%s%d%d",op[i],&lt[i],&rt[i]);
        if(op[i][0]=='Q') scanf("%d",&K[i]);
        else
            a[++len]=rt[i];
    }
    sort(a+1,a+len+1);
    len=unique(a+1,a+len+1)-a-1;
    for(int i=1; i<=n; i++) num[i]=lower_bound(a+1,a+1+len,num[i])-a;
    build(1,len,T[0]);
    for(int i=1; i<=n; i++) BIT(i,num[i],1);
    for(int i=1; i<=m; i++)
        if(op[i][0]=='Q')
            printf("%d\n",a[BIT_query(lt[i]-1,rt[i],K[i])]);
        else
        {
            BIT(lt[i],num[lt[i]],-1);
            int pos=lower_bound(a+1,a+len+1,rt[i])-a;
            num[lt[i]]=pos;
            BIT(lt[i],pos,1);
        }
    return 0;
}

posted on 2013-10-02 16:45  仗剑奔走天涯  阅读(325)  评论(0编辑  收藏  举报

导航