题目大意
H国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构。伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了H国的必修技能。有一天,邪恶的“卡”带着他的邪恶的“常数”来企图毁灭H国。“卡”给H国的人洗脑说,splay如果写成单旋的,将会更快。“卡”称“单旋splay”为“spaly”。虽说他说的很没道理,但还是有H国的人相信了,小H就是其中之一,spaly马上成为他的信仰。而H国的国王,自然不允许这样的风气蔓延,国王构造了一组数据,数据由m(不超过10^5)个操作构成,他知道这样的数据肯定打垮spaly,但是国王还有很多很多其他的事情要做,所以统计每个操作所需要的实际代价的任务就交给你啦。数据中的操作分为5种:
1. 插入操作:向当前非空spaly中插入一个关键码为key的新孤立节点。插入方法为,先让key和根比较,如果key比根小,则往左子树走,否则往右子树走,如此反复,直到某个时刻,key比当前子树根x小,而x的左子树为空,那就让key成为x的左孩子;或者key比当前子树根x大,而x的右子树为空,那就让key成为x的右孩子。该操作的代价为:插入后,key的深度。特别地,若树为空,则直接让新节点成为一个单个节点的树。(各节点关键码互不相等。对于“深度”的解释见末尾对spaly的描述。)
2. 单旋最小值: 将spaly中关键码最小的元素xmin单旋到根。操作代价为:单旋前xmin 的深度。(对于单旋操作的解释见末尾对spaly的描述。)
3. 单旋最大值: 将spaly中关键码最大的元素xmax单旋到根。操作代价为:单旋前xmax的深度。
4. 单旋删除最小值:先执行2号操作,然后把根删除。由于2号操作之后,根没有左子树,所以直接切断根和右子树的联系即可。(具体见样例解释)。操作代价同2号操作。
5. 单旋删除最大值:先执行3号操作,然后把根删除。操作代价同3号操作。
6. 对于不是H国的人,你可能需要了解一些spaly的知识,才能完成国王的任务:
a. spaly是一棵二叉树,满足对于任意一个节点x,它如果有左孩子lx,那么lx的关键码小于x的关键码。如果有右孩子rx,那么rx的关键码大于x的关键码。
b. 一个节点在spaly的深度定义为:从根节点到该节点的路径上一共有多少个节点(包括自己)。
c. 单旋操作是对于一棵树上的节点x来说的。一开始,设f为x在树上的父亲。如果x为f的左孩子,那么执行zig(x)操作(如上图中,左边的树经过zig(x)变为了右边的树), 否则执行zag(x)操作(在上图中,将右边的树经过zag(f)就变成了左边的树)。每当执行一次zig(x)或者zag(x), x的深度减小1,如此反复,直到x为根。总之,单旋x就是通过反复执行zig和zag将x变为根。
解题思路
将点离散化,用数组维护father和son[0,1],用线段树维护dep。考虑到插入只会插入在权值相邻的两个节点,用set维护直接插入。
考虑旋到根,自己的深度变为1,非子树节点的深度+1。考虑删除,子树节点深度-1.用线段树维护即可。
code
#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LD double
#define LL long long
#define ULL unsigned long long
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std ;
int const mm=1e5 +9 ,inf=1e9 ;
int m,top,op[mm],key[mm],a[mm],tag[mm*4 ],size[mm*4 ],dep2[mm],fa[mm],son[mm][2 ];
int retag(int now){
tag[now*2 ]+=tag[now];
tag[now*2 +1 ]+=tag[now];
tag[now]=0 ;
}
int vis(int now,int l,int r,int v){
int mid=(l+r)>>1 ;
if (l==r){
dep2[l]=tag[now];
return (size[now])?l:0 ;
}
retag(now);
if (mid<v)return vis(now*2 +1 ,mid+1 ,r,v);
else return vis(now*2 ,l,mid,v);
}
void add(int now,int l,int r,int u,int v){
int mid=(l+r)>>1 ;
if (l==r){
tag[now]=(v>0 )?v:0 ;
size[now]=v>0 ;
return ;
}
retag(now);
if (u<=mid)add(now*2 ,l,mid,u,v);
else add(now*2 +1 ,mid+1 ,r,u,v);
size[now]=size[now*2 ]+size[now*2 +1 ];
}
void up(int now,int l,int r,int u,int v,int w){
int mid=(l+r)>>1 ;
if ((l==u)&&(r==v)){
tag[now]+=w;
return ;
}
retag(now);
if (v<=mid)up(now*2 ,l,mid,u,v,w);
else if (mid<u)up(now*2 +1 ,mid+1 ,r,u,v,w);
else {
up(now*2 ,l,mid,u,mid,w);
up(now*2 +1 ,mid+1 ,r,mid+1 ,v,w);
}
}
multiset <int > s;
int main(){
freopen("d.in" ,"r" ,stdin);
freopen("d.out" ,"w" ,stdout);
scanf ("%d" ,&m);
fo(i,1 ,m){
scanf ("%d" ,&op[i]);
if (op[i]==1 ){
scanf ("%d" ,&key[i]);
a[++a[0 ]]=key[i];
}
}
sort(a+1 ,a+a[0 ]+1 );
fo(i,1 ,m)if (key[i])key[i]=lower_bound(a+1 ,a+a[0 ]+1 ,key[i])-a;
fo(i,1 ,m){
if (op[i]==1 ){
int tmp,tmp2,tmp3=1 ;
if (s.empty())tmp=tmp2=0 ;
else {
multiset <int > ::iterator x=s.lower_bound(key[i]);
if (x!=s.end()){
tmp2=*x;
if (x==s.begin())tmp=0 ;
else tmp=*(--x);
}
else {
tmp2=0 ;
if (x==s.begin())tmp=0 ;
else tmp=*(--x);
}
}
if (tmp)vis(1 ,1 ,a[0 ],tmp);if (tmp2)vis(1 ,1 ,a[0 ],tmp2);
if (tmp&&(!son[tmp][1 ])){
fa[key[i]]=tmp;
son[tmp][1 ]=key[i];
tmp3=dep2[tmp]+1 ;
}else if (tmp2){
fa[key[i]]=tmp2;
son[tmp2][0 ]=key[i];
tmp3=dep2[tmp2]+1 ;
}else top=key[i];
add(1 ,1 ,a[0 ],key[i],tmp3);
printf ("%d\n" ,tmp3);s.insert(key[i]);
}else if (op[i]==2 ){
int tmp=*s.begin(),tmp2=top,tmp3=fa[tmp];
vis(1 ,1 ,a[0 ],tmp);
printf ("%d\n" ,dep2[tmp]);
if (!tmp3)continue ;
up(1 ,1 ,a[0 ],tmp3,a[0 ],1 );
add(1 ,1 ,a[0 ],tmp,1 );
son[tmp3][0 ]=son[tmp][1 ];
if (son[tmp][1 ])fa[son[tmp][1 ]]=tmp3;
fa[tmp2]=tmp;
son[tmp][1 ]=tmp2;
fa[tmp]=0 ;top=tmp;
}else if (op[i]==3 ){
int tmp=*(--s.end()),tmp2=top,tmp3=fa[tmp];
vis(1 ,1 ,a[0 ],tmp);
printf ("%d\n" ,dep2[tmp]);
if (!tmp3)continue ;
up(1 ,1 ,a[0 ],1 ,tmp3,1 );
add(1 ,1 ,a[0 ],tmp,1 );
son[tmp3][1 ]=son[tmp][0 ];
if (son[tmp][0 ])fa[son[tmp][0 ]]=tmp3;
fa[tmp2]=tmp;
son[tmp][0 ]=tmp2;
fa[tmp]=0 ;top=tmp;
}else if (op[i]==4 ){
int tmp=*s.begin(),tmp2=fa[tmp];
vis(1 ,1 ,a[0 ],tmp);s.erase(s.begin());
printf ("%d\n" ,dep2[tmp]);
if (!tmp2){
top=son[tmp][1 ];
add(1 ,1 ,a[0 ],tmp,-1 );
fa[tmp]=fa[son[tmp][1 ]]=0 ;
if (tmp!=a[0 ])up(1 ,1 ,a[0 ],tmp+1 ,a[0 ],-1 );
continue ;
}
if (tmp+1 <tmp2)up(1 ,1 ,a[0 ],tmp+1 ,tmp2-1 ,-1 );
add(1 ,1 ,a[0 ],tmp,-1 );
son[tmp2][0 ]=son[tmp][1 ];
if (son[tmp][1 ])fa[son[tmp][1 ]]=tmp2;
}else {
int tmp=*(--s.end()),tmp2=fa[tmp];
vis(1 ,1 ,a[0 ],tmp);s.erase(--s.end());
printf ("%d\n" ,dep2[tmp]);
if (!tmp2){
top=son[tmp][0 ];
add(1 ,1 ,a[0 ],tmp,-1 );
fa[tmp]=fa[son[tmp][0 ]]=0 ;
if (tmp!=1 )up(1 ,1 ,a[0 ],1 ,tmp-1 ,-1 );
continue ;
}
if (tmp2+1 <tmp)up(1 ,1 ,a[0 ],tmp2+1 ,tmp-1 ,-1 );
add(1 ,1 ,a[0 ],tmp,-1 );
son[tmp2][1 ]=son[tmp][0 ];
if (son[tmp][0 ])fa[son[tmp][0 ]]=tmp2;
}
}
return 0 ;
}