数据结构--树状数组套主席树(动态区间k小)

给大家一波福利,我在洛谷上放了一道bzoj权限题
传送门
都不要说,要不我会被打。。。
有人说的话,我就删了这题了。。
然后就是这个题就是个模板题,直接板子。
我的封装过了,看一看细节,直接用就好了。
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N=1e4+5;
const int M=N*300;
struct node{
    int ls,rs,size;
}t[M];
int n,m,cnt,tot;
int a[N],b[N<<1];
inline int Hash(int x){
    return lower_bound(b+1,b+cnt+1,x)-b;
}
struct Q{
    int opt,A,B,K;
}q[N];
struct bit_seg{
    int add[30],mns[30],cnt1,cnt2;
    int root[N];
    inline int lowbit(int x){
        return x&-x;
    }
    inline void insert(int num,int &now,int l,int r,int val){
        t[++tot]=t[now];
        now=tot;
        t[now].size+=val;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(num<=mid)insert(num,t[now].ls,l,mid,val);
        else insert(num,t[now].rs,mid+1,r,val);
    }
    inline int query(int l,int r,int k){
        if(l==r)return b[l];
        int lsize=0;
        for(int i=1;i<=cnt1;i++)lsize+=t[t[add[i]].ls].size;
        for(int i=1;i<=cnt2;i++)lsize-=t[t[mns[i]].ls].size;
        int mid=(l+r)>>1;
        if(k<=lsize){
            for(int i=1;i<=cnt1;i++)add[i]=t[add[i]].ls;
            for(int i=1;i<=cnt2;i++)mns[i]=t[mns[i]].ls;
            return query(l,mid,k);
        }
        else{
            for(int i=1;i<=cnt1;i++)add[i]=t[add[i]].rs;
            for(int i=1;i<=cnt2;i++)mns[i]=t[mns[i]].rs;
            return query(mid+1,r,k-lsize);
        }
    }
    inline void build(){
        for(int i=1;i<=n;i++){
            a[i]=Hash(a[i]);
            for(int j=i;j<=n;j+=lowbit(j)){
                insert(a[i],root[j],1,cnt,1);
            }
        }
    }
    inline int Query(int l,int r,int k){
        cnt1=cnt2=0;
        for(int i=l-1;i;i-=lowbit(i))mns[++cnt2]=root[i];
        for(int i=r;i;i-=lowbit(i))add[++cnt1]=root[i];
        return query(1,cnt,k);
    }
    inline void Insert(int pos,int x){
        for(int i=pos;i<=n;i+=lowbit(i)){
            insert(a[pos],root[i],1,cnt,-1);
        }
        a[pos]=Hash(x);
        for(int i=pos;i<=n;i+=lowbit(i)){
            insert(a[pos],root[i],1,cnt,1);
        }
    }
}tree;
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        a[i]=read();b[++cnt]=a[i];
    }
    for(int i=1;i<=m;i++){
        char ch[3];
        scanf("%s",ch);
        if(ch[0]=='Q'){
            q[i].opt=0;q[i].A=read();q[i].B=read();q[i].K=read();
        }
        else{
            q[i].opt=1;q[i].A=read();q[i].B=read();b[++cnt]=q[i].B;
        }
    }
    sort(b+1,b+cnt+1);
    cnt=unique(b+1,b+cnt+1)-b-1;
    tree.build();
    for(int i=1;i<=m;i++){
        if(q[i].opt){
            tree.Insert(q[i].A,q[i].B);
        }
        else{
            printf("%d\n",tree.Query(q[i].A,q[i].B,q[i].K));
        }
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值