
#include <iostream>
using namespace std;
const int N=100005;
struct node{
int l,r; //左右儿子
int val; //树的权值
int rnd; //堆的随机值
int size; //子树大小
}tr[N];
int root,idx;
void newnode(int &x,int v){
x = ++idx;
tr[x].val=v;
tr[x].rnd=rand();
tr[x].size=1;
}
void pushup(int p){
tr[p].size=tr[tr[p].l].size+tr[tr[p].r].size+1;
}
void split(int p,int v,int &x,int &y){
if(!p) {x=y=0; return;}
if(tr[p].val<=v){
x = p;
split(tr[x].r,v,tr[x].r,y);
pushup(x);
}
else{
y = p;
split(tr[y].l,v,x,tr[y].l);
pushup(y);
}
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(tr[x].rnd<tr[y].rnd){
tr[x].r=merge(tr[x].r,y);
pushup(x); return x;
}
else{
tr[y].l=merge(x,tr[y].l);
pushup(y); return y;
}
}
void insert(int v){
int x,y,z;
split(root,v,x,y);
newnode(z,v);
root=merge(merge(x,z),y);
}
void del(int v){
int x,y,z;
split(root,v,x,z);
split(x,v-1,x,y);
y=merge(tr[y].l,tr[y].r);
root=merge(merge(x,y),z);
}
int getrank(int v){
int x,y;
split(root,v-1,x,y);
int ans=tr[x].size+1;
root=merge(x,y);
return ans;
}
int getval(int root,int v){
if(v==tr[tr[root].l].size+1)
return tr[root].val;
else if(v<=tr[tr[root].l].size)
return getval(tr[root].l,v);
else
return getval(tr[root].r,v-tr[tr[root].l].size-1);
}
int getpre(int v){
int x,y,s,ans;
split(root,v-1,x,y);
s=tr[x].size;
ans=getval(x,s);
root=merge(x,y);
return ans;
}
int getnxt(int v){
int x,y,ans;
split(root,v,x,y);
ans=getval(y,1);
root=merge(x,y);
return ans;
}
int main(){
int n,op,v;
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d",&op,&v);
if(op==1)insert(v);
else if(op==2)del(v);
else if(op==3)printf("%d\n",getrank(v));
else if(op==4)printf("%d\n",getval(root,v));
else if(op==5)printf("%d\n",getpre(v));
else printf("%d\n",getnxt(v));
}
return 0;
}
注意:分裂操作中传的是指针,在分裂的过程中节点的左右儿子会随之改变,x,y就是起到这样的作用
同时他是一个二叉搜索树,所以中序遍历是有序序列
key的随机值是为了实现堆的性质,其实是感觉可能性的,尽量随机打乱谁在上谁在下

#include <iostream>
using namespace std;
const int N=100010;
struct node{
int l,r; //左右儿子
int val; //树的权值
int key; //堆的随机值
int size; //子树大小
int tag; //懒标记
}tr[N];
int n,m,root,idx;
int newnode(int v){
tr[++idx].val=v;
tr[idx].key=rand();
tr[idx].size=1;
return idx;
}
void pushup(int p){
tr[p].size=tr[tr[p].l].size
+tr[tr[p].r].size+1;
}
void pushdown(int p){
if(!tr[p].tag||!p) return;
swap(tr[p].l, tr[p].r);
tr[tr[p].l].tag ^= 1;
tr[tr[p].r].tag ^= 1;
tr[p].tag = 0;
}
void split(int p,int k,int &x,int &y){
if(!p) {x=y=0; return;}
pushdown(p);
if(k>tr[tr[p].l].size){
k-=tr[tr[p].l].size+1;
x=p;
split(tr[p].r,k,tr[p].r,y);
}
else{
y=p;
split(tr[p].l,k,x,tr[p].l);
}
pushup(p);
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(tr[x].key<tr[y].key){
pushdown(x);
tr[x].r=merge(tr[x].r,y);
pushup(x); return x;
}
else{
pushdown(y);
tr[y].l=merge(x,tr[y].l);
pushup(y); return y;
}
}
void reverse(int l,int r){
int x,y,z;
split(root,r,x,z);
split(x,l-1,x,y);
tr[y].tag ^= 1; //标记
root=merge(merge(x,y),z);
}
void output(int p){
if(!p) return;
pushdown(p);
output(tr[p].l);
printf("%d ",tr[p].val);
output(tr[p].r);
}
int main(){
srand(time(0));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
root=merge(root,newnode(i));
for(int x,y,i=1;i<=m;i++){
scanf("%d%d",&x,&y);
reverse(x, y);
}
output(root);
return 0;
}
重点在于问题不同,他要的是翻转这个下标序号的位置,应该对这些节点的所处的位置进行操作,而不是原来那种对他的值val进行比较。