//Treap fhq版(不旋转) //所有操作依靠split()(分离)和merge()(合并)完成 //可支持区间操作和可持久化 比普通Treap更通用 //所有Treap中序遍历均为递增序列 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> using namespace std; int n,cnt,size,root,x,y,z; //x为小Treap的根节点 y为中Treap的根节点 z为大Treap的根节点 root为总Treap的根节点 int son[100001][2],siz[100001],val[100001],rd[100001]; //左右儿子,子树大小+自己大小,点值,随机权值 int new_node(int m)//建立新节点 { siz[++size]=1; val[size]=m; rd[size]=rand(); return size; } void update(int now) { siz[now]=siz[son[now][0]]+siz[son[now][1]]+1; } void split(int now,int k,int &a,int &b) { if(!now) { a=b=0; return; } if(val[now]<=k) a=now,split(son[now][1],k,son[now][1],b); //将此节点及其左子树接到小Treap上,并遍历此节点的右节点 else b=now,split(son[now][0],k,a,son[now][0]); //将此节点及其右子树接到大Treap上,并遍历此节点的左节点 update(now); } int merge(int a,int b) { if(!a||!b) return a+b; if(rd[a]<rd[b]) { son[a][1]=merge(son[a][1],b); //将小Treap节点及其左子树接在总Treap上,并遍历此节点的右节点 update(a); return a; } else { son[b][0]=merge(a,son[b][0]); //将大Treap节点及其右子树接在总Treap上,并遍历此节点的左节点 update(b); return b; } } int k_th(int now,int k) { while(1) { if(k<=siz[son[now][0]]) now=son[now][0]; else if(k==siz[son[now][0]]+1) return now; else { k-=siz[son[now][0]]+1; now=son[now][1]; } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int u,k; scanf("%d%d",&u,&k); if(u==1)//插入 { split(root,k,x,z);//先分成两个Treap 此时k(若有)在小Treap中 root=merge(merge(x,new_node(k)),z);//重新合并 } if(u==2)//删除 { split(root,k,x,z);//先分成两个Treap 此时k在小Treap中 split(x,k-1,x,y);//再把小Treap分成两个Treap 此时k在中Treap中 且为中Treap根节点 y=merge(son[y][0],son[y][1]);//把中Treap根节点的两个子树合并 此时已删除k root=merge(merge(x,y),z);//重新合并 } if(u==3)//查找权值为k的排名 { split(root,k-1,x,z);//先分成两个Treap 此时小Treap中包含了所有小于k的数 printf("%d\n",siz[x]+1);//k的排名即为小于k的权值数目+1 root=merge(x,z);//重新合并 } if(u==4)//查找排名为k的权值 printf("%d\n",val[k_th(root,k)]);//直接输出 if(u==5)//求前驱 { split(root,k-1,x,z);//先分成两个Treap 此时k是大Treap中最小的数 printf("%d\n",val[k_th(x,siz[x])]);//前驱即为小Treap中最大的数 即最右节点 root=merge(x,z);//重新合并 } if(u==6)//求后继 { split(root,k,x,z);//先分成两个Treap 此时k是小Treap中最大的数 printf("%d\n",val[k_th(z,1)]);//后继即为大Treap中最小的数 即最左节点 root=merge(x,z);//重新合并 } } return 0; }
原文地址:https://www.cnblogs.com/water-radish/p/9280878.html
时间: 2024-10-19 00:24:35