Treap,入门级平衡树的一种。它通过适当的单旋转,在维持节点关键码满足BST性质的同时,还使每个节点上随机生成的额外权值满足堆的性质。
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
const int INF=0x7fffffff;
const int N=2000010;
struct Node
{
int l,r;
int key,cnt,size;
unsigned int val;
}tr[N];
int root,tot;
mt19937 mt_rand(time(0));
int New(int key)
{
tr[++tot].key=key;
tr[tot].val=mt_rand();
tr[tot].cnt=tr[tot].size=1;
return tot;
}
void pushup(int p)
{
tr[p].size=tr[tr[p].l].size+tr[tr[p].r].size+tr[p].cnt;
}
void zig(int &p) //右旋
{
int q=tr[p].l;
tr[p].l=tr[q].r,tr[q].r=p,p=q;
pushup(tr[p].r),pushup(p);
}
void zag(int &p) //左旋
{
int q=tr[p].r;
tr[p].r=tr[q].l,tr[q].l=p;p=q;
pushup(tr[p].l),pushup(p);
}
void build()
{
New(-INF),New(INF);
root=1,tr[root].r=2;
pushup(root);
if(tr[1].val<tr[2].val)zag(root);
}
void insert(int &p,int key)
{
if(!p)p=New(key);
else if(tr[p].key==key)++tr[p].cnt;
else if(tr[p].key>key)
{
insert(tr[p].l,key);
if(tr[tr[p].l].val>tr[p].val)zig(p);
}
else
{
insert(tr[p].r,key);
if(tr[tr[p].r].val>tr[p].val)zag(p);
}
pushup(p);
}
void erase(int &p,int key)
{
if(!p)return;
if(tr[p].key==key)
{
if(tr[p].cnt>1)--tr[p].cnt;
else if(tr[p].l||tr[p].r)
{
if(!tr[p].r||tr[tr[p].l].val>tr[tr[p].r].val)
{
zig(p);
erase(tr[p].r,key);
}
else zag(p),erase(tr[p].l,key);
}
else p=0; //已经是叶子节点,删除
}
else if(tr[p].key>key)erase(tr[p].l,key);
else erase(tr[p].r,key);
pushup(p);
}
int get_rank(int p,int key)
{
if(!p)return 1; //出现这种情况意味着不存在key,应该返回1
if(tr[p].key==key)return tr[tr[p].l].size+1;
if(tr[p].key>key)return get_rank(tr[p].l,key);
return tr[tr[p].l].size+tr[p].cnt+get_rank(tr[p].r,key);
}
int get_key(int p,int rank)
{
if(!p)return INF; //不存在排名为rank的数,返回正无穷
if(tr[tr[p].l].size>=rank)return get_key(tr[p].l,rank);
if(tr[tr[p].l].size+tr[p].cnt>=rank)return tr[p].key;
return get_key(tr[p].r,rank-tr[tr[p].l].size-tr[p].cnt);
}
int get_pre(int p,int key)
{
if(!p)return -INF; //不存在前驱,返回负无穷
if(tr[p].key>=key)return get_pre(tr[p].l,key);
return max(tr[p].key,get_pre(tr[p].r,key));
}
int get_nxt(int p,int key)
{
if(!p)return INF; //不存在后继,返回正无穷
if(tr[p].key<=key)return get_nxt(tr[p].r,key);
return min(tr[p].key,get_nxt(tr[p].l,key));
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
build();
int n,m,x;
cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>x;
insert(root,x);
}
int last=0,ans=0;
while(m--)
{
int op,x;
cin>>op>>x;
x^=last;
if(op==1)insert(root,x);
else if(op==2)erase(root,x);
else if(op==3)last=(get_rank(root,x)-1);
else if(op==4)last=get_key(root,x+1);//因为有哨兵的存在
else if(op==5)last=get_pre(root,x);
else last=get_nxt(root,x);
if(op>=3)ans^=last;
}
cout<<ans<<'\n';
return 0;
}