支持修改的主席树,例题:zoj2112

一些名字和解释:传送门
例题:zoj2112
代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=60060;
int cnt,n,m,x,y,k,tmp,root[N],spt[N],a[N];
int cmp;
struct node{int l,r,sum;}T[N*40];
struct Op{int l,r,k,type;}op[N];
vector<int>Q1,Q2;
vector<int> p;
int getid(int x) {return lower_bound(p.begin(),p.end(),x)-p.begin()+1;}
int lowbit(int x) {return -x&x;}
void update(int l,int r,int &x,int y,int pos )
{
    T[++cnt]=T[y],T[cnt].sum++,x=cnt;
    if(l==r) return ;
    int mid=(r+l)>>1;
    if(pos<=mid) update(l,mid,T[x].l,T[y].l,pos);
    else  update(mid+1,r,T[x].r,T[y].r,pos);
}
void insert(int l,int r,int &i,int x,int val)
{
    if(i==0) T[++cnt]=T[i],i=cnt;
    T[i].sum+=val;
    if(l==r) return ;
    int mid=(r+l)>>1;
    if(x<=mid)insert(l,mid,T[i].l,x,val);
    else insert(mid+1,r,T[i].r,x,val);
}
void BIT_insert(int pos,int x,int val)
{
    for(int i=pos;i<=tmp;i+=lowbit(i))
        insert(1,tmp,spt[i],x,val);
}
int ST_query(vector<int> Q1,vector<int> Q2,int l,int r,int k)
{
    if(l==r) return l;
    int c=0;
    int mid=(r+l)>>1;
    for(int i=0,sz=Q1.size();i<sz;i++) c-=T[T[Q1[i]].l].sum;
    for(int i=0,sz=Q2.size();i<sz;i++) c+=T[T[Q2[i]].l].sum;
    for(int i=0,sz=Q1.size();i<sz;i++) Q1[i]=(c>=k?T[Q1[i]].l:T[Q1[i]].r);
    for(int i=0,sz=Q2.size();i<sz;i++) Q2[i]=(c>=k?T[Q2[i]].l:T[Q2[i]].r);
    if(c>=k) return ST_query(Q1,Q2,l,mid,k);
    else return ST_query(Q1,Q2,mid+1,r,k-c);
}
int query(int l,int r,int k)
{
    Q1.clear(),Q2.clear();
    Q1.push_back(root[l-1]);
    Q2.push_back(root[r]);
    for(int i=l-1;i>0;i-=lowbit(i)) Q1.push_back(spt[i]);
    for(int i=r;i>0;i-=lowbit(i)) Q2.push_back(spt[i]);
    return ST_query(Q1,Q2,1,tmp,k);
}
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        cnt=0;
        memset(root,0,sizeof(root));
        memset(spt,0,sizeof(spt));
        p.clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),p.push_back(a[i]);
        char str[4];
        for(int i=1;i<=m;i++)
        {
            scanf("%s",str);
            if(str[0]=='Q')
            {
                op[i].type=1;
                scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);
            }
            else
            {
                op[i].type=0;
                scanf("%d%d",&op[i].l,&op[i].r);
                p.push_back(op[i].r);
            }
        }
        sort(p.begin(),p.end()),p.erase(unique(p.begin(),p.end()),p.end());
        tmp=p.size();
        for(int i=1;i<=n;i++) update(1,tmp,root[i],root[i-1],getid(a[i]));
        for(int i=1;i<=m;i++)
        {
            if(op[i].type==1)
            {
                printf("%d\n",p[query(op[i].l,op[i].r,op[i].k)-1]);
            }
            else
            {
                BIT_insert(op[i].l,getid(a[op[i].l]),-1);
                BIT_insert(op[i].l,getid(op[i].r),1);
                a[op[i].l]=op[i].r;
            }
        }

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值