原来线段树还有这种操作(开成一个桶)
用区间维护在这个区间内元素的个数,离散化一下,居然能达到splay的效果
不仅码量大大减少,而且跑的飞快!!!
6种操作 200多ms
- 插入 xx 数
- 删除 xx 数(若有多个相同的数,因只删除一个)
- 查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 。若有多个相同的数,因输出最小的排名)
- 查询排名为 xx 的数
- 求 xx 的前驱(前驱定义为小于 xx ,且最大的数)
- 求 xx 的后继(后继定义为大于 xx ,且最小的数)
#include<cstdio> #include<iostream> #include<cctype> #include<algorithm> using namespace std; #define int long long #define ls (o<<1) #define rs (ls|1) int b[100500]; int a[100500]; int val[100500]; int st[405000]; int n; int tot; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { putchar('-'); x=-x; } if(x>9) put(x/10); putchar(x%10+'0'); } inline void add_or_del(int o,int l,int r,int k,int pos) { st[o]+=pos; if(l==r) return; int mid=(l+r)>>1; if(k<=mid) add_or_del(ls,l,mid,k,pos); else add_or_del(rs,mid+1,r,k,pos); } inline int x_rank_n(int o,int l,int r,int k) { if(l==r) return 1; int mid=(l+r)>>1; if(k<=mid) return x_rank_n(ls,l,mid,k); else return st[ls]+x_rank_n(rs,mid+1,r,k); } inline int n_rank_x(int o,int l,int r,int k) { if(l==r) return l; int mid=(l+r)>>1; if(st[ls]>=k) return n_rank_x(ls,l,mid,k); else return n_rank_x(rs,mid+1,r,k-st[ls]); } signed main() { n=read(); for(int i=1;i<=n;i++) { val[i]=read(); a[i]=read(); if(val[i]!=4) b[++tot]=a[i]; } sort(b+1,b+tot+1); for(int i=1;i<=n;i++) { if(val[i]!=4) a[i]=lower_bound(b+1,b+tot+1,a[i])-b; } for(int i=1;i<=n;i++) { switch(val[i]) { case 1: add_or_del(1,1,tot,a[i],1);break; case 2: add_or_del(1,1,tot,a[i],-1);break; case 3: put(x_rank_n(1,1,tot,a[i]));putchar(' ');break; case 4: put(b[n_rank_x(1,1,tot,a[i])]);putchar(' ');break; case 5: put(b[n_rank_x(1,1,tot,x_rank_n(1,1,tot,a[i])-1)]);putchar(' ');break; default: put(b[n_rank_x(1,1,tot,x_rank_n(1,1,tot,a[i]+1))]);putchar(' '); } } return 0; }
so good。。。