bzoj3224 Tyvj 1728 普通平衡树 (权值线段树 模板题)

问题描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个)
  3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数)
  6. 求x的后继(后继定义为大于x,且最小的数)
Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案

Sample Input

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

Sample Output

106465
84185
492737

Hint

1.n的数据范围:n<=100000

2.每个数的数据范围:[-2e9,2e9]

分析:

模板题,不多bb

特判一下查询排名1的数,不然死循环

前驱和后继用了rank+kth代替,不过调用了两个函数,
(也有一个函数直接求的方法,应该比这样快,但是没这个无脑)

code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
const int maxm=3e5+5;
struct Query{
    int d,x;
}q[maxm];
int a[maxm<<2];
int xx[maxm],num;
void build(int l,int r,int node){
    a[node]=0;
    if(l==r)return ;
    int mid=(l+r)/2;
    build(l,mid,node*2);
    build(mid+1,r,node*2+1);
}
void update(int x,int val,int l,int r,int node){
    a[node]+=val;
    if(l==r)return ;
    int mid=(l+r)/2;
    if(x<=mid)update(x,val,l,mid,node*2);
    else update(x,val,mid+1,r,node*2+1);
}
int ask(int st,int ed,int l,int r,int node){
    if(st<=l&&ed>=r)return a[node];
    int mid=(l+r)/2;
    int ans=0;
    if(st<=mid)ans+=ask(st,ed,l,mid,node*2);
    if(ed>=mid+1)ans+=ask(st,ed,mid+1,r,node*2+1);
    return ans;
}
int kth(int k,int l,int r,int node){
    if(l==r)return l;
    int mid=(l+r)/2;
    if(a[node*2]>=k)return kth(k,l,mid,node*2);
    return kth(k-a[node*2],mid+1,r,node*2+1);
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>q[i].d>>q[i].x;
        if(q[i].d!=4){
            xx[++num]=q[i].x;
        }
    }
    sort(xx+1,xx+1+num);
    num=unique(xx+1,xx+1+num)-xx-1;
    build(1,num,1);
    for(int i=1;i<=n;i++){
        int d=q[i].d;
        int x=q[i].x;
        if(d!=4)x=lower_bound(xx+1,xx+1+num,x)-xx;
        if(d==1){//插入
            update(x,1,1,num,1);
        }else if(d==2){//删除
            update(x,-1,1,num,1);
        }else if(d==3){//x的排名
            cout<<(x-1?ask(1,x-1,1,num,1)+1:1)<<endl;//如果x-1等于0则排名为1
        }else if(d==4){//排第x的
            cout<<xx[kth(x,1,num,1)]<<endl;
        }else if(d==5){//前驱
            int p=ask(1,x-1,1,num,1);
            cout<<xx[kth(p,1,num,1)]<<endl;
        }else{//后继
            int p=ask(1,x,1,num,1);
            cout<<xx[kth(p+1,1,num,1)]<<endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值