可持久化平衡树 LUOGU P-3835
/* 这道题一看可以知道是平衡树+持久化.如果是持久化, 那么我们就要保存历史信息,每次修改logn个点,所以内存要靠2nlogn. split是把以i为根节点的子树分成两部分,一部分小于等于k,一部分大于k,必须保证其BST所有的性质 merge是合并以x为根节点和以y为根节点的两颗子树。 */ #include<bits/stdc++.h> using namespace std; const int N=5e5+5; struct node{ int l,r; int v,rd,sum; }a[N*50]; int cnt; void update(int i){ if(!i)return ; a[i].sum=a[a[i].l].sum+a[a[i].r].sum+1; } int newnode(int x){ ++cnt; a[cnt].l=a[cnt].r=0; a[cnt].sum=1;a[cnt].v=x; a[cnt].rd=rand(); return cnt; } int merge(int x,int y){//合并操作,按照treap的rd的优先级来合并(小跟堆或大根堆都行) //这里是大根堆 if(!x||!y)return x+y; if(a[x].rd>a[y].rd){ int p=++cnt;a[p]=a[x]; a[p].r=merge(a[p].r,y); update(p);return p; } else { int p=++cnt;a[p]=a[y]; a[p].l=merge(x,a[p].l); update(p);return p; } } void split(int now,int k,int &x,int &y){//把小于等于k的数放x子树里面,大于k的放y子树里面 if(now==0){x=y=0;return ;} if(a[now].v<=k){ x=++cnt;a[x]=a[now]; split(a[x].r,k,a[x].r,y); update(x); } else { y=++cnt;a[y]=a[now]; split(a[y].l,k,x,a[y].l); update(y); } } void insert(int &root,int v){//插入一个新结点 int x=0,y=0,z=0; split(root,v-1,x,y); z=newnode(v); root=merge(merge(x,z),y); } void del(int &root,int v){//删除一个结点 int x=0,y=0,z=0; split(root,v,x,z); split(x,v-1,x,y); y=merge(a[y].l,a[y].r); root=merge(merge(x,y),z); } int rank_value(int i,int k){ if(k==a[a[i].l].sum+1)return a[i].v; if(k<=a[a[i].l].sum)return rank_value(a[i].l,k); return rank_value(a[i].r,k-a[a[i].l].sum-1); } int kth_rank(int &root,int v){//查询排名为x的数 int x,y; split(root,v-1,x,y); int ans=a[x].sum+1; root=merge(x,y); return ans; } int pre(int &root,int v){//求前驱 int x,y,k; split(root,v-1,x,y); if(x==0)return -2147483647; k=a[x].sum; int ans=rank_value(x,k); root=merge(x,y); return ans; } int nex(int &root,int v){//求后驱 int x,y,ans; split(root,v,x,y); if(y==0)return 2147483647; ans=rank_value(y,1); root=merge(x,y); return ans; } int n,root[N]; int main(){ scanf("%d",&n); int x,y,op; for(int i=1;i<=n;i++){ scanf("%d%d%d",&x,&op,&y); root[i]=root[x]; if(op==1)insert(root[i],y); if(op==2)del(root[i],y); if(op==3)printf("%d\n",kth_rank(root[i],y)); if(op==4)printf("%d\n",rank_value(root[i],y)); if(op==5)printf("%d\n",pre(root[i],y)); if(op==6)printf("%d\n",nex(root[i],y)); } return 0; }