P3835 【模板】可持久化平衡树
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
-
插入x数
-
删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
-
查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
-
查询排名为x的数
-
求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)
-
求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
每个版本的编号即为操作的序号(版本0即为初始状态,空树)
输入输出格式
输入格式:
第一行包含一个正整数N,表示操作的总数。
接下来每行包含三个正整数,第 i 行记为 vi,opti,xi。
vi表示基于的过去版本号( 0≤vi<i ),opti 表示操作的序号( 1≤opt≤6 ), xi 表示参与操作的数值
输出格式:
每行包含一个正整数,依次为各个3,4,5,6操作所对应的答案
输入输出样例
说明
数据范围:
对于28%的数据满足: 1≤n≤10
对于44%的数据满足: 1≤n≤2⋅102
对于60%的数据满足: 1≤n≤3⋅103
对于84%的数据满足: 1≤n≤105
对于92%的数据满足: 1≤n≤2⋅105
对于100%的数据满足:1≤n≤5⋅105 , −109≤xi≤109
经实测,正常常数的可持久化平衡树均可通过,请各位放心
样例说明:
共10次操作,11个版本,各版本的状况依次是:
-
[][]
-
[9][9]
-
[3, 9][3,9]
-
[9, 10][9,10]
-
[3, 9][3,9]
-
[9, 10][9,10]
-
[2, 9, 10][2,9,10]
-
[2, 9, 10][2,9,10]
-
[2, 10][2,10]
-
[2, 10][2,10]
-
[3, 9][3,9]
Solution:
本题可持久化平衡树板子题(没啥好写的)。
我们先用无旋treap打下普通平衡树那道板子题,那么可持久化无非是在之前版本的状态基础上每次新开节点记录新的状态就好了。
于是只需要每次改为新建节点去merge,改为新建节点去split,记录每个版本的树根就好了(感觉很简单啊)。
代码:
/*Code by 520 -- 9.26*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=5e5+5,inf=0x7fffffff; int n,root[N],cnt; struct node{ int ls,rs,siz,date,rnd; }t[N*50]; int gi(){ int a=0;char x=getchar();bool f=0; while((x<'0'||x>'9')&&x!='-') x=getchar(); if(x=='-') x=getchar(),f=1; while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar(); return f?-a:a; } il int newnode(int v){ ++cnt; t[cnt].date=v,t[cnt].siz=1,t[cnt].rnd=rand(); return cnt; } il void up(int rt){t[rt].siz=t[t[rt].ls].siz+t[t[rt].rs].siz+1;} int merge(int x,int y){ if(!x||!y) return x+y; if(t[x].rnd<t[y].rnd){ int p=++cnt;t[p]=t[x]; t[p].rs=merge(t[p].rs,y); up(p); return p; } else { int p=++cnt;t[p]=t[y]; t[p].ls=merge(x,t[p].ls); up(p); return p; } } void split(int rt,int k,int &x,int &y){ if(!rt) {x=y=0;return;} if(t[rt].date<=k){ x=++cnt;t[x]=t[rt]; split(t[x].rs,k,t[x].rs,y); up(x); } else { y=++cnt;t[y]=t[rt]; split(t[y].ls,k,x,t[y].ls); up(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(t[y].ls,t[y].rs); root=merge(x,merge(y,z)); } void ins(int &root,int v){ int x=0,y=0; split(root,v,x,y); root=merge(x,merge(newnode(v),y)); } il int kth(int rt,int v){ while(1){ if(v<=t[t[rt].ls].siz) rt=t[rt].ls; else if(v>t[t[rt].ls].siz+1) v-=t[t[rt].ls].siz+1,rt=t[rt].rs; else return t[rt].date; } } il int id(int &root,int v){ int x=0,y=0,ans; split(root,v-1,x,y); ans=t[x].siz+1; root=merge(x,y); return ans; } il int pre(int &root,int v){ int x=0,y=0,ans; split(root,v-1,x,y); if(!x) return -inf; ans=kth(x,t[x].siz); root=merge(x,y); return ans; } il int suc(int &root,int v){ int x=0,y=0,ans; split(root,v,x,y); if(!y) return inf; ans=kth(y,1); root=merge(x,y); return ans; } int main(){ srand(time(0)); n=gi(); int v,opt,x; For(i,1,n){ v=gi(),opt=gi(),x=gi(); root[i]=root[v]; if(opt==1) ins(root[i],x); if(opt==2) del(root[i],x); if(opt==3) printf("%d\n",id(root[i],x)); if(opt==4) printf("%d\n",kth(root[i],x)); if(opt==5) printf("%d\n",pre(root[i],x)); if(opt==6) printf("%d\n",suc(root[i],x)); } return 0; }