HYSBZ 1901 Dynamic Rankings

题意:
给定一个长度为n的序列,有m次操作,分别为以下两种情况:
1.Q left right k,查询[left,right]中的第k小数
2.C at data,将第x位的数修改为data
题解:
①带修改的主席树=主席树+树状数组
②与POJ 2104 K-th Number类似,只不过加上了修改操作
③考虑每一次修改操作,实际上它只会对[at,n]的区间产生影响
④我们可以开一个树状数组来记录这些修改,树状数组的每一个点都是一颗线段树
⑤查询的时候只要将原来的查询加上树状数组上的查询即可


 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=50000+10;
struct Tree{
        int lch,rch;
        int data;
}a[maxn<<5];
struct ASK{
        int op;
        int left,right,k;
        int at,data;
}q[maxn];
int n,m,A[maxn];
int Map[maxn],cnt;
int root[maxn],num;
int C[maxn],use[maxn];
void Init();
void Build(int&,int,int);
void Update(int&,int,int,int,int,int);
int Query(int,int,int,int,int,int,int);
int Lowbit(int);
void Add(int,int,int);
int GetSum(int);
signed main(){
        // freopen("in.cpp","r",stdin);
        int t;scanf("%d",&t);
        while(t--)Init();
        return 0;
}
void Init(){
        num=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
                scanf("%d",&A[i]),Map[++cnt]=A[i];
        char op;
        for(int i=1;i<=m;i++){
                scanf(" %c",&op);
                if(op=='Q')q[i].op=1,scanf("%d%d%d",&q[i].left,&q[i].right,&q[i].k);    
                else q[i].op=0,scanf("%d%d",&q[i].at,&q[i].data),Map[++cnt]=q[i].data;
        }
        sort(Map+1,Map+1+cnt);cnt=unique(Map+1,Map+1+cnt)-Map-1;
        Build(root[0],1,cnt);
        for(int i=1;i<=n;i++){
                int x=lower_bound(Map+1,Map+1+cnt,A[i])-Map;
                Update(root[i],root[i-1],1,cnt,x,1);
        }
        for(int i=1;i<=n;i++)C[i]=root[0];
        for(int i=1,x;i<=m;i++){
                if(q[i].op){
                        for(int j=q[i].left-1;j;j-=Lowbit(j))
                                use[j]=C[j];
                        for(int j=q[i].right;j;j-=Lowbit(j))
                                use[j]=C[j];
                        x=Query(root[q[i].left-1],root[q[i].right],q[i].left-1,q[i].right,1,cnt,q[i].k);
                        printf("%d\n",Map[x]);
                }
                else{
                        x=lower_bound(Map+1,Map+1+cnt,A[q[i].at])-Map;
                        Add(q[i].at,x,-1);
                        x=lower_bound(Map+1,Map+1+cnt,q[i].data)-Map;
                        Add(q[i].at,x,1);
                        A[q[i].at]=q[i].data;
                }
        }
}
void Build(int &u,int left,int right){
        u=++num;
        a[u].data=0;
        if(left==right)return;
        int mid=(left+right)>>1;
        Build(a[u].lch,left,mid);
        Build(a[u].rch,mid+1,right);
}
void Update(int &u,int y,int left,int right,int pos,int key){
        u=++num;
        a[u].lch=a[y].lch;a[u].rch=a[y].rch;
        a[u].data=a[y].data+key;
        if(left==right)return;
        int mid=(left+right)>>1;
        if(pos<=mid)Update(a[u].lch,a[y].lch,left,mid,pos,key);
        else Update(a[u].rch,a[y].rch,mid+1,right,pos,key);
}
int Query(int u,int v,int L,int R,int left,int right,int k){
        if(left==right)return left;
        int mid=(left+right)>>1;
        int data=GetSum(R)-GetSum(L)+a[a[v].lch].data-a[a[u].lch].data;
        if(data>=k){
                for(int i=L;i;i-=Lowbit(i))
                        use[i]=a[use[i]].lch;
                for(int i=R;i;i-=Lowbit(i))
                        use[i]=a[use[i]].lch;
                return Query(a[u].lch,a[v].lch,L,R,left,mid,k);
        }
        else{ 
                for(int i=L;i;i-=Lowbit(i))
                        use[i]=a[use[i]].rch;
                for(int i=R;i;i-=Lowbit(i))
                        use[i]=a[use[i]].rch;
                return Query(a[u].rch,a[v].rch,L,R,mid+1,right,k-data);
        }
}
int Lowbit(int x){
        return x&(-x);
}
void Add(int x,int pos,int key){
        for(int i=x;i<=n;i+=Lowbit(i))
                Update(C[i],C[i],1,cnt,pos,key);
}
int GetSum(int x){
        int ans=0;
        for(int i=x;i;i-=Lowbit(i))
                ans+=a[a[use[i]].lch].data;
        return ans;
}

 

posted @ 2018-08-21 11:22  holy-unicorn  阅读(136)  评论(0编辑  收藏  举报