BZOJ1901(主席树+树状数组 实现“动态主席树”)


BZOJ1901: Zju2112 Dynamic Rankings

  Time Limit: 10 Sec
  Memory Limit: 128 MB

Description

   给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。
 

Input

   第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。
  第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。
  接下来的m行描述每条指令
  每行的格式是下面两种格式中的一种。
  Q i j k 或者 C i t
  Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)
  表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
  C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t
  m,n≤10000
 

Output

   对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
 

Sample Input

   5 3
   3 2 1 4 7
   Q 1 4 3
   C 2 6
   Q 2 5 3
 

Sample Output

  3
  6
    

HINT

题目地址:BZOJ1901: Zju2112 Dynamic Rankings

题目大意: 题目很简洁了:)

题解:

  对于不修改的情况
  我们对每一个数都开一颗主席树(这里第i颗主席树记录前i个数的情况)
  只要对目标区间的左右端点的主席树差分下就能求出 \(kth\)
  如何支持动态
  想到树状数组可以 \(logN\) 支持前缀和
  我们只要像树状数组一样开主席树就可以了
  例如第 \(c[8]\) 颗主席树记录的是 \(c[4]\)颗和\(c[6]\)颗和\(c[7]\)颗和第 \(8\) 个数的情况
p1
  对于每次修改只要修改 \(logN\)颗主席树,修改每个主席树上 \(logN\)个点
  然后 orz hzw


AC代码

#include <cstdio> 
#include <algorithm>
using namespace std;
const int N=1e4+5,M=2200001;
int n,m,tot,Lnum,Rnum;
int val[N],K[N],hash[N<<1],A[N],B[N];
char op[N];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int sz,sum[M],son[M][2],root[N];
void change(int u,int &v,int l,int r,int k,int x){
    v=++sz;
    sum[v]=sum[u]+x;
    son[v][0]=son[u][0];
    son[v][1]=son[u][1];
    if(l==r)return;
    int mid=(l+r)>>1;
    if(k<=mid)change(son[u][0],son[v][0],l,mid,k,x);
    else change(son[u][1],son[v][1],mid+1,r,k,x);
}
int L[30],R[30];
int query(int l,int r,int k){
    if(l==r)return l;
    int suml=0,sumr=0;
    for(int i=1;i<=Lnum;i++)suml+=sum[son[L[i]][0]];
    for(int i=1;i<=Rnum;i++)sumr+=sum[son[R[i]][0]];
    int mid=(l+r)>>1;
    if(sumr-suml>=k){
        for(int i=1;i<=Lnum;i++)L[i]=son[L[i]][0];
        for(int i=1;i<=Rnum;i++)R[i]=son[R[i]][0];
        return query(l,mid,k);
    }else{
        for(int i=1;i<=Lnum;i++)L[i]=son[L[i]][1];
        for(int i=1;i<=Rnum;i++)R[i]=son[R[i]][1];
        return query(mid+1,r,k-(sumr-suml));
    }
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        val[i]=hash[++tot]=read();
    for(int i=1;i<=m;i++){
        scanf("\n");
        op[i]=getchar();
        A[i]=read(),B[i]=read();
        if(op[i]=='Q')K[i]=read();
        else hash[++tot]=B[i];
    }
    sort(hash+1,hash+tot+1);
    int New=unique(hash+1,hash+tot+1)-hash-1;
    for(int i=1;i<=n;i++){
        int k=lower_bound(hash+1,hash+New+1,val[i])-hash;
        for(int j=i;j<=n;j+=j&(-j))
            change(root[j],root[j],1,New,k,1);
    }
    for(int i=1;i<=m;i++)
        if(op[i]=='Q'){
            Lnum=0,Rnum=0;A[i]--;
            for(int j=A[i];j>0;j-=j&(-j))
                L[++Lnum]=root[j];
            for(int j=B[i];j>0;j-=j&(-j))
                R[++Rnum]=root[j];
            printf("%d\n",hash[query(1,New,K[i])]);
        }else{
            int k;
            k=lower_bound(hash+1,hash+New+1,val[A[i]])-hash;
            for(int j=A[i];j<=n;j+=j&(-j))
                change(root[j],root[j],1,New,k,-1);
            val[A[i]]=B[i];
            k=lower_bound(hash+1,hash+New+1,B[i])-hash;
            for(int j=A[i];j<=n;j+=j&(-j))
                change(root[j],root[j],1,New,k,1);
        }
    return 0;
}


  作者:skl_win
  出处:https://www.cnblogs.com/shaokele/
  本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted @ 2018-10-03 21:58  skl_win  阅读(...)  评论(...编辑  收藏
Live2D