Treap树:平衡树的一种
数和堆的集合,每个节点有值,也有优先级,那么这棵树的形态就被确定了,和插入顺序无关了(有赖于优先级
避免退化成链:在生成节点时,随机生成优先级,然后插入时动态调整
删除:如果有两个子节点,找到优先级大的,把x向反方向旋转,也就是把x向树的下层调整,直到旋转到叶子节点
!很多题目涉及名次树
常用操作:
struct node,旋转rotate,插入insert(),查找第k大的数kth(),查询某个数find()【名次树】
旋转zig(右旋)/tag(左旋)操作
splay树和treap树https://www.cnblogs.com/shirlybaby/p/12393268.html
【一本通】
1565:【例 1】营业额统计


有很多种方法
第一种方法;直接用set做
但是注意一点(怎么看出来的...)就是有一个点差一个输入,其他直接lowerbound\upperbound就可以了
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//可以用set过
//有一个点少了一个输入的样子
set<int> st;
int n,x;
int main(){
scanf("%d",&n);
int ans;
scanf("%d",&x);
ans=x;
st.insert(INF);
st.insert(-INF);
//插入正无穷和负无穷,防止迭代器访问到一些奇奇怪怪的内存
st.insert(x); //第一个单独考虑
for(int i=1;i<n-1;i++){
scanf("%d",&x);
int l=*(--st.lower_bound(x)); //大于等于(第一个)所以减一就是小于
int r=*st.lower_bound(x); //大于
if(x-l>r-x) ans+=r-x;
else ans+=x-l;
st.insert(x);
}
if(scanf("%d",&x)==1){
int l=*(--st.lower_bound(x));
int r=*st.lower_bound(x);
if(x-l>r-x) ans+=r-x;
else ans+=x-l;
st.insert(x);
}
else{
x=0;
int l=*(--st.lower_bound(x));
int r=*st.lower_bound(x);
if(x-l>r-x) ans+=r-x;
else ans+=x-l;
st.insert(x);
}
printf("%d\n",ans);
return 0;
}
第二种方法:离线+排序
用链表做,不容易想到
首先排序,然后插入链表
r[i]表示原来的a[i]在链表中的位置
倒序处理,把r[i]的ans贡献算出来,然后删除r[i]指向的位置
为什么这样可行呢?
因为是离线+排序,所以每个元素之间的关系是已知的
倒序处理时,对于每个a[i],链表就是前i个元素组成的【学会呀!】
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
/*
首先排序,然后插入链表
r[i]表示原来的a[i]在链表中的位置
倒序处理,把r[i]的ans贡献算出来,然后删除r[i]指向的位置
为什么这样可行呢?
因为是离线+排序,所以每个元素之间的关系是已知的
倒序处理时,对于每个a[i],链表就是前i个元素组成的
*/
typedef unsigned long long ull;
struct node{
int pre,next;
}b[32768];
struct data{
int d;
int rak;
}a[32768];
int r[32768];
int n,ans;
bool cmp(data x,data y){
if(x.d!=y.d) return x.d<y.d;
else return x.rak<y.rak;
}
void del(int x){
b[b[x].next].pre=b[x].pre;
b[b[x].pre].next=b[x].next;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].d);
a[i].rak=i;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
r[a[i].rak]=i; //r[]表示的是原来的下标在现在的排名
if(i!=n) b[i].next=i+1;
b[i].pre=i-1;
}
int j,k;
for(int i=n;i;i--){
j=0;k=0;
int x=r[i]; //原来的输入里面第i个现在的排名
if(b[x].pre) j=abs(a[b[x].pre].d-a[x].d);
else j=INF;
if(b[x].next) k=abs(a[b[x].next].d-a[x].d);
else k=INF;
if(i!=1) ans+=min(j,k);
else ans+=a[x].d;
del(x);
r[i]=0;
}
printf("%d\n",ans);
return 0;
}
第三种方法:splay树
提根操作!左右旋操作,这个不好写也不好记
注意如果发现已经有这个数的话,就不要再计算前驱和后继了,肯定加的是0
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=100100;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//第三种做法 平衡树 splay
int root,tot;
struct tree{
int key;
int son[2]; //son[0]左儿子,son[1]右儿子
int fa;
}T[maxn];
void newnode(int &r,int w,int fa){
r=++tot;
T[r].key=w;
T[r].fa=fa;
T[r].son[0]=T[r].son[1]=0;
}
void rotat(int r,int kind){ //旋转,kind为1是右旋,为0是左旋
int y=T[r].fa;
T[y].son[!kind]=T[r].son[kind];
T[T[r].son[kind]].fa=y;
if(T[y].fa)
T[T[y].fa].son[T[T[y].fa].son[1]==y]=r;
T[r].fa=T[y].fa;
T[r].son[kind]=y;
T[y].fa=r;
}
void splay(int r,int goal){ //Splay调整,将结点r调整到goal下面(以r为根节点)
int y;
while(T[r].fa!=goal){
y=T[r].fa;
if(T[y].fa==goal) rotat(r,T[y].son[0]==r); //如果是左子树就右旋 右子树就左旋
//如果现在的爸爸的爸爸就是目标的话,就旋转
else{
int kind=T[T[y].fa].son[0]==y;
if(T[y].son[kind]==r){
rotat(r,!kind);
rotat(r,kind);
}
else{
rotat(y,kind);
rotat(r,kind);
}
}
}
if(goal==0) root=r; //更新根节点
}
bool inser(int w){
int r=root;
while(T[r].son[w>T[r].key]){
if(T[r].key==w){ //如果w已经在树中
splay(r,0); //移到树根
return false; //返回0,不用继续插入了
}
r=T[r].son[w>T[r].key]; //如果大的话,就插入右子树(1),小的话就插入左子树(0)
}
newnode(T[r].son[w>T[r].key],w,r); //插在r相应的子树里面 void newnode(int &r,int w,int fa)
splay(T[r].son[w>T[r].key],0);
//移动到树根
return true;
}
int get_pre(int r){ //在左子树中找到最大的值(找前驱)
int temp=T[r].son[0];
if(temp==0) return INF;
while(T[temp].son[1]) //在左子树的右子树里面寻找
temp=T[temp].son[1];
return T[r].key-T[temp].key;
}
int get_next(int r){ //在右子树中找到最小的值(找后继)
int temp=T[r].son[1];
if(temp==0) return INF;
while(T[temp].son[0])
temp=T[temp].son[0];
return T[temp].key-T[r].key;
}
int main(){
int n,x;
scanf("%d",&n);
int ans=0;
scanf("%d",&x);
ans=x;
newnode(root,x,0);
for(int i=1;i<n;i++){
scanf("%d",&x);
if(!inser(x)) continue;
ans+=min(get_pre(root),get_next(root));
}
printf("%d\n",ans);
return 0;
}
第四种方法:treap树
每次取出新读入数据的前驱与后继,与该数据差值较小的就是。(注意若已有同一个数据,特判ans+=0)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int maxn=5e5+10;
const int INF=0x3f3f3f3f;
struct node{
int lc,rc,fa,pos,vis; //pos是优先级 vis是权值
#define lc(x) t[x].lc
#define rc(x) t[x].rc
#define fa(x) t[x].fa
#define pos(x) t[x].pos
#define vis(x) t[x].vis
}t[maxn];
int n,rt,ans;
inline void zig(int &x){ //右旋
int y=lc(x); //让x的左子树当爸爸
lc(x)=rc(y);
rc(y)=x;
x=y;
}
inline void zag(int &x){ //左旋
int y=rc(x);
rc(x)=lc(y);
lc(y)=x;
x=y;
}
inline void inse(int&x,const int vi){
if(!x){
vis(x=++ans)=vi;
pos(x)=rand();
return;
}
if(vi<vis(x)){
inse(lc(x),vi);
if(pos(x)>pos(lc(x))) zig(x); //往左子树插了之后马上检查heap
}
else{
inse(rc(x),vi);
if(pos(x)>pos(rc(x))) zag(x);
}
}
inline int querypre(const int vi){ //找前驱
int x=rt,pr=-INF;
while(x){
if(vi>=vis(x)) pr=vis(x),x=rc(x);
else x=lc(x);
}
return pr;
}
inline int querynex(const int vi){ //找后继
int x=rt,nex=INF;
while(x){
if(vi<=vis(x)) nex=vis(x),x=lc(x);
else x=rc(x);
}
return nex;
}
int main(){
cin>>n;
int x;
cin>>x;
inse(rt,x);
int res=x;
while(--n){
cin>>x;
int xx=querypre(x);
int yy=querynex(x);
res+=min(x-xx,yy-x);
inse(rt,x);
}
cout<<res<<endl;
return 0;
}
还有第五种方法是线段树、第六种替罪羊树(不知道没写了)
1566:宠物收养所
这道题和前面一道很相似,都是需要计算相差最小的前驱和后继,适合使用treap或者splay这样的数据结构
这个跟 营业额统计 那题差不多,多了个标记。标记一下当前这个树里的是人还是狗。判断一下当前操作的与树里的是不是同种生物,然后相应做出处理就好了。
首先是treap的做法
#include<bits/stdc++.h>
using namespace std;
const int N=80005;
const int mod=1000000;
const int inf=1e9;
int n,ans,a,b,R,sum,num[N];
int ch[N][2],size[N],val[N],rd[N];
void rotate(int &q,int d)
{
int k=ch[q][d];
ch[q][d]=ch[k][d^1];
ch[k][d^1]=q;
size[k]=size[q];
size[q]=size[ch[q][0]]+size[ch[q][1]]+1;
q=k;
}
void ins(int &q,int x)
{
if(!q)
{
q=++sum;
size[q]=1;val[q]=x;
rd[q]=rand(); return;
}
size[q]++;
if(val[q]<x)
{
ins(ch[q][1],x);
if(rd[q]>rd[ch[q][1]]) rotate(q,1);
}
else
{
ins(ch[q][0],x);
if(rd[q]>rd[ch[q][0]]) rotate(q,0);
}
}
void del(int &q,int x)
{
if(!q) return;
if(val[q]==x)
{
if(ch[q][0]==0||ch[q][1]==0) q=ch[q][0]+ch[q][1];
else if(rd[ch[q][0]]<rd[ch[q][1]]) rotate(q,0),del(q,x);
else rotate(q,1),del(q,x);
}
else
{
size[q]--;
if(val[q]>x) del(ch[q][0],x);
else del(ch[q][1],x);
}
}
int qq(int q,int x)
{
if(!q) return -inf;
if(val[q]>x) return qq(ch[q][0],x);
else return max(val[q],qq(ch[q][1],x));
}
int hq(int q,int x)
{
if(!q) return inf;
if(val[q]<x) return hq(ch[q][1],x);
else return min(val[q],hq(ch[q][0],x));
}
int main()
{
scanf("%d",&n);int c=-1;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
if(c==a) ins(R,b);
else if(size[R]){
int hhh=qq(R,b),ggg=hq(R,b);
if(b-hhh<=ggg-b) ans=(ans+b-hhh)%mod,del(R,hhh);
else ans=(ans+ggg-b)%mod,del(R,ggg);
}
else c=a,ins(R,b);
}
printf("%d",ans);
return 0;
}
第二种方法:splay树
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX 200000
#define MOD 1000000
int tot;
inline int read()
{
register int x=0,t=1;
register char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-'){t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*t;
}
struct Node
{
int ch[2];
int val;
int ff;
}t[MAX];
int root;
inline void rotate(int x)
{
int y=t[x].ff;
int z=t[y].ff;
int k=(x==t[y].ch[1]);
t[z].ch[y==t[z].ch[1]]=x;
t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];
t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;
t[y].ff=x;
}
inline void splay(int x,int goal)
{
//if(x==0)return;
while(t[x].ff!=goal)
{
int y=t[x].ff;
int z=t[y].ff;
if(z!=goal)
(t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);
rotate(x);
}
if(goal==0)root=x;
}
inline void insert(int x)
{
int u=root,ff=0;
while(u&&t[u].val!=x)
{
ff=u;
u=t[u].ch[t[u].val<x];
}
if(u);
else
{
u=++tot;
if(ff)t[ff].ch[t[ff].val<x]=u;
t[u].ff=ff;
t[u].ch[0]=t[u].ch[1]=0;
t[u].val=x;
}
splay(u,0);
}
inline void find(int x)
{
int u=root;
if(!u)return;
while(t[u].ch[x>t[u].val]&&x!=t[u].val)
u=t[u].ch[x>t[u].val];
splay(u,0);
}
inline int Next(int x,int f)
{
find(x);
int u=root;
if(t[u].val>=x&&f)return u;
if(t[u].val<=x&&!f)return u;
u=t[u].ch[f];
while(t[u].ch[f^1])u=t[u].ch[f^1];
return u;
}
inline int Next_une(int x,int f)
{
find(x);
int u=root;
if(t[u].val>x&&f)return u;
if(t[u].val<x&&!f)return u;
u=t[u].ch[f];
while(t[u].ch[f^1])u=t[u].ch[f^1];
return u;
}
inline void Delete(int x)
{
int lt=Next_une(x,0);
int nt=Next_une(x,1);
splay(lt,0);splay(nt,lt);
t[nt].ch[0]=0;
}
int main()
{
int n=read();
int cnt=0,ans=0;
insert(+214748364);
insert(-214748364);
while(n--)
{
int k=read(),x=read();
if(x==1)
x=1;
if(cnt==0)//空树
insert(x);
if(cnt>0)//宠物树
{
if(k==0)insert(x);
else//新来顾客
{
int a1=t[Next(x,0)].val;//前驱
int a2=t[Next(x,1)].val;//后继
if(abs(a1-x)<=abs(a2-x))
{
ans+=abs(a1-x);
Delete(a1);
}
else
{
(ans+=abs(a2-x))%=MOD;
Delete(a2);
}
}
}
if(cnt<0)//顾客树
{
if(k==1)insert(x);
else//新来宠物
{
int a1=t[Next(x,0)].val;
int a2=t[Next(x,1)].val;
if(abs(a1-x)<=abs(a2-x))
{
(ans+=abs(a1-x))%=MOD;
Delete(a1);
}
else
{
(ans+=abs(a2-x))%=MOD;
Delete(a2);
}
}
}
cnt=cnt+(k==0?1:-1);
}
printf("%d\n",ans);
return 0;
}
1567:郁闷的出纳员


其实看题目就能够明白:需要做的事有增加或减少每一个节点的值,增加节点、删除节点,查询排名为第k的人的值
节点的值是会动态改变,还可能动态删除的,而重点是这道题想问当前工资第k多的员工所拿的工资数
先写一个最简单的vector https://www.sogou.com/link?url=hedJjaC291P3yGwc7N55kLSc2ls_Ks2xYJXKjZDwcU0p1wk5xGC9fwNZoNd2gwAGIeZ8aQ291kY.
/*
vector通过lower_bound和insert操作能够维护一个有序递减/递增的线性表
insert复杂度虽然是O(n),实际表现却非常快(可以看做sqrt(n)),配合lower_bound能够做到许多事情
在这道题中,我们重载了lower_bound的<运算符,维护一个单调递减的序列
ps
erase的复杂度为O(n),因为是区间删除,我们要避免用erase操作,注意到删除的区间是序列中最小的一段区间,考虑用O(1)的pop_back
pop_back的复杂度是O(1),元素总数不超过100000,故删除操作总复杂度为O(N)
查询元素总数时,我们也不用STL的size()(单次复杂度O(N)),而是手动维护一个siz变量
但是我对delta偏移的用法还不是很懂
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e6+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
int n,m;
int k;
vector<int> q;
bool cmp(int a,int b) {
return a>b;
}
int delta=0; //用这个记录偏移 就是增加或者减小的工资
int main(){
scanf("%d %d",&n,&m);
char op;
int size=0,ans=0; //手动维护集合大小
for(int i=0;i<n;i++){
scanf(" %c",&op);
scanf("%d",&k);
switch(op){
case 'I':{
if(k>=m){
q.insert(lower_bound(q.begin(),q.end(),k-delta,cmp),k-delta); //为什么插入的是k-delta
size++;
}
break;
}
case 'A':
delta+=k;break;
case 'S':{
delta-=k;
int it=upper_bound(q.begin(),q.end(),m-delta,cmp)-q.begin(); //为什么比较的是m-delta
while(size!=it) {
q.pop_back();
ans++;
size--;
}
break;
}
case 'F':{
if(size<k) printf("-1\n");
else printf("%d\n",q[k-1]+delta);
break;
}
}
}
printf("%d\n",ans);
return 0;
}
第二种方法:splay
#include<cstdio>
#define maxn 100009
using namespace std;
struct splay{
int l, r, fa, size, v, time;
}node[maxn];
int root = 0, cnt = 0, change = 0, p = 0, n, small;
inline void update(int x){node[x].size = node[node[x].l].size + node[node[x].r].size + node[x].time;}
void zig(int x){
int F = node[x].fa, G = node[F].fa;
if (G){
if (node[G].l == F) node[G].l = x;
else node[G].r = x;
}
node[x].fa = G;
node[F].l = node[x].r;
if (node[x].r) node[node[x].r].fa = F;
node[F].fa = x;
node[x].r = F;
}
void zag(int x){
int F = node[x].fa, G = node[F].fa;
if (G){
if (node[G].l == F) node[G].l = x;
else node[G].r = x;
}
node[x].fa = G;
node[F].r = node[x].l;
if (node[x].l) node[node[x].l].fa = F;
node[F].fa = x;
node[x].l = F;
}
void Splay(int x, int s = 0){
while (node[x].fa != s){
int F = node[x].fa, G = node[F].fa;
if (G == s){
if (node[F].l == x) zig(x); else zag(x);
update(F);
break;
}
else{
if (node[F].l == x){
if (node[G].l == F){zig(F); zig(x);}
else{zig(x);zag(x);}
}
else{
if (node[G].r == F){zag(F); zag(x);}
else{zag(x); zig(x);}
}
update(G);
update(F);
}
}
update(x);
if (!s) root = x;
}
int find(int x){
int p = root;
while (p && node[p].v != x){
if (x > node[p].v) p = node[p].r; else p = node[p].l;
}
if (p) Splay(p);
return p;
}
void insert(int x){
if (!root){node[++cnt] = (splay){0, 0, 0, 1, x, 1}; root = cnt; return;}
int p = root, p2;
while (p){
if (x == node[p].v) {++node[p].time;update(p); Splay(p);break;}
else if (x > node[p].v) p2 = node[p].r;
else p2 = node[p].l;
if (!p2){
node[++cnt] = (splay){0, 0, p, 1, x, 1};
if (x > node[p].v) node[p].r = cnt;
else node[p].l = cnt;
update(p);
Splay(cnt);
break;
}
p = p2;
}
}
int getKth(int k){
int p = root;
while (k){
int size = node[node[p].l].size, time = node[p].time;
if (size + time < k) {p = node[p].r; k -= size + time;}
else if (size >= k) p = node[p].l;
else return node[p].v;
}
}
void del(){
int p = root, p2 = root, ch = small - change;
while(p){
if (node[p].v < ch) p = node[p].r;
else{p2 = p; p = node[p].l;}
}
if (node[p2].v < ch) {root = 0;return;}
Splay(p2);
node[p2].l = 0;
update(p2);
}
int read(){
char c;
while (c = getchar(), c < '0' || c > '9');
int x = c - '0';
while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0';
return x;
}
int main(){
char c; int x;
node[0] = (splay){0, 0, 0, 0, 0, 0};
n = read(); small = read();
while(n--){
while (c = getchar(), !(c >= 'A' && c <= 'Z'));
x = read();
switch(c){
case 'I':if (x >= small) {++p;insert(x - change);};break;
case 'A':change += x;break;
case 'S':change -= x; del();break;
case 'F':if (x > node[root].size) printf("-1\n");
else printf("%d\n", getKth(node[root].size - x + 1) + change);break;
}
}
printf("%d\n", p - node[root].size);
return 0;
}
1568:普通平衡树
这是一道模板题。
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

treap的模板
https://www.cnblogs.com/Y-Knightqin/p/12252930.html
#include <bits/stdc++.h>
#define maxn 100010
#define inf 0x3f3f3f3f
using namespace std;
//https://www.cnblogs.com/Y-Knightqin/p/12252930.html
int key[maxn],cnt[maxn],ran[maxn],siz[maxn],son[maxn][2],op,n,num=0,x,root=0;
void pushup(int x)
{
siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x];
}
void rotate(int &x,int op)
{
int p=son[x][!op];
son[x][!op]=son[p][op];
son[p][op]=x;
pushup(x);
pushup(p);
x=p;
}
void insert(int &k,int x)
{
if (k==0)
{
k=++num;
cnt[k]=1;
key[k]=x;
ran[k]=rand();
siz[k]=1;
return;
}
else if (key[k]==x)
{
cnt[k]++;
siz[k]++;
return;
}
int op=(x>key[k]);
insert(son[k][op],x);
if (ran[son[k][op]]<ran[k]) rotate(k,!op);
pushup(k);
}
void _delete(int &k,int x)
{
if (k==0) return;
if (x!=key[k])
{
int op=(x>key[k]);
_delete(son[k][op],x);
pushup(k);
return;
}
if (cnt[k]>1)
{
cnt[k]--;
siz[k]--;
pushup(k);
return;
}
if (!son[k][0]&&son[k][1])
{
rotate(k,0);
_delete(son[k][0],x);
}
else if (son[k][0] && !son[k][1])
{
rotate(k,1);
_delete(son[k][1],x);
}
else if (!son[k][0] && !son[k][1])
{
cnt[k]--;
siz[k]--;
if (cnt[k]==0) k=0;
}
else
{
int op=(ran[son[k][0]]>ran[son[k][1]]);
rotate(k,!op);
_delete(son[k][!op],x);
}
pushup(k);
}
int rank(int k,int x)
{
if (k==0) return 0;
if (key[k]==x) return siz[son[k][0]]+1;
if (key[k]>x) return rank(son[k][0],x);
return siz[son[k][0]]+cnt[k]+rank(son[k][1],x);
}
int find(int k,int x)
{
if (k==0) return 0;
if (siz[son[k][0]]>=x) return find (son[k][0],x);
else if (siz[son[k][0]]+cnt[k]<x) return find (son[k][1],x-siz[son[k][0]]-cnt[k]);
else return key[k];
}
int lowerbound(int k,int x)
{
if (k==0) return -inf;
if (key[k]>=x) return lowerbound(son[k][0],x);
else return max(key[k],lowerbound(son[k][1],x));
}
int upperbound(int k,int x)
{
if (k==0) return inf;
if (key[k]<=x) return upperbound(son[k][1],x);
else return min(key[k],upperbound(son[k][0],x));
}
int main()
{
cin>>n;
while (n--)
{
scanf("%d%d",&op,&x);
switch(op)
{
case 1:insert(root,x);break;
case 2:_delete(root,x);break;
case 3:printf("%d\n",rank(root,x));break;
case 4:printf("%d\n",find(root,x));break;
case 5:printf("%d\n",lowerbound(root,x));break;
case 6:printf("%d\n",upperbound(root,x));break;
}
}
return 0;
}
里面还写了一个懒人版treap,用vector实现的
#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 4e5+5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
vector<int>v;
int t,opt,x;
int main()
{
t=read();
while(t--)
{
opt=read(),x=read();
if(opt==1) v.insert(lower_bound(v.begin(),v.end(),x),x);
if(opt==2) v.erase (lower_bound(v.begin(),v.end(),x));
if(opt==3) printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
if(opt==4) printf("%d\n",v[x-1]);
if(opt==5) printf("%d\n",v[lower_bound(v.begin(),v.end(),x)-v.begin()-1]);
if(opt==6) printf("%d\n",v[upper_bound(v.begin(),v.end(),x)-v.begin()]);
}
return 0;
}
posted on
浙公网安备 33010602011771号