题目链接
详细请自己去看题面。
题意:
对于一颗只能进行单旋操作的splay(题中叫spaly),有如下四个操作:
1.插入一个节点,代价为插入后节点的深度。
2.把最小值旋到根,代价为其原来的深度。
3.把最大值旋到根,代价为其原来的深度。
4.进行2操作后把根节点删掉。
5.进行3操作后把根节点删掉。
一道看起来有点滑稽的题,显然不是用splay做啦 OVO
一看只要旋最大值和最小值,那么旋的时候肯定是一条链上去啦。
再手玩一下,发现转了后树的形态基本没变,只是把最小值(最大值)的右儿子(左儿子)接到父节点的左儿子(右儿子)上,再直接把该节点放到根上就OK啦。
深度怎么求呢? LCT即可,维护size。
插入呢,难道O(logn)?(显然实际是O(n)),发现好像是前驱和后继中深度大的那个点。set搞起。
但是还有一个问题,原splay中的树的形态是必须要维护的,因为不然就不知道怎么cut了。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
int x=0;char ch=getchar();int t=1;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
return x*t;
}
const int N=1e5+10;
#define __ NULL
#define Pr pair
#define fi first
#define se second
#define ls son[0]
#define rs son[1]
#define get_size(a) (a==__? 0:a->size)
#define get_son(a) (a->fa->rs==a)
struct node{
node* fa;node* son[2];bool is_root;bool rev;int size;
inline void clear(){fa=ls=rs=__;size=1;rev=0;is_root=1;}
}*tr[N];
int root;
node pool[N];int cnt=0;
int m;
node* st[N];
int Fa[N];
int LS[N];
int RS[N];//用于维护实际Spaly的形态
inline void updata(node* p){if(p==__) return;p->size=1+get_size(p->ls)+get_size(p->rs);}
inline void push_down(node* p)
{
if(p==__||p->rev==0) return;p->rev=0;
if(p->ls!=__) p->ls->rev^=1;
if(p->rs!=__) p->rs->rev^=1;
swap(p->ls,p->rs);
}
void push(node* p){int top;st[top=1]=p;while(!p->is_root) st[++top]=(p=p->fa);while(top) push_down(st[top--]);}
inline void rotate(node* p)
{
if(p==__||p->is_root) return;
register node* q=p->fa;register node* gp=q->fa;
register int k=get_son(p);
q->son[k]=p->son[k^1];
if(p->son[k^1]!=__) p->son[k^1]->fa=q;p->fa=gp;
if(q->is_root) q->is_root=0,p->is_root=1;
else if(gp!=__) gp->son[get_son(q)]=p;
q->fa=p;p->son[k^1]=q;
updata(q);
return;
}
inline void Splay(node* p)
{
if(p==__) return;push(p);
for(;!p->is_root;rotate(p)){
if(p->fa->is_root) continue;
if(get_son(p)==get_son(p->fa)) rotate(p->fa);
else rotate(p);
}
updata(p);
}
inline void access(node* p)
{
for(register node* pre=__;p!=__;pre=p,p=p->fa){
Splay(p);if(p->rs!=__) p->rs->is_root=1;p->rs=pre;
if(pre!=__) pre->is_root=0;updata(p);
}
}
inline void m_root(node* p){access(p);Splay(p);p->rev^=1;}
inline void split(node* p,node* q){m_root(p);access(q);Splay(q);}
inline void Link(node* p,node* q){m_root(p);p->fa=q;}
inline void Cut(node* p,node* q){split(p,q);if(q->ls==p) p->fa=q->ls=__,p->is_root=1,updata(q);}
set S;
set ::iterator it;
int ans=0;
inline int Dep(node* p,node* q){split(p,q);return q->size;}
inline void Add(int x)
{
++cnt;tr[cnt]=&pool[cnt];tr[cnt]->clear();
Pr p=Pr(x,cnt);
if(S.empty()) {S.insert(p);root=cnt;ans=1;return;}
int a=0;x=0;int b=0,y=0;
it=S.insert(p).fi;
if(it!=S.begin()) {p=*(--it);a=p.se;x=Dep(tr[root],tr[a]);++it;}
++it;
if(it!=S.end()) {p=*it;b=p.se;y=Dep(tr[root],tr[b]);}
if(x>y) Fa[cnt]=a,RS[a]=cnt,Link(tr[a],tr[cnt]);//接在前驱和后继中深度较大的点上
else Fa[cnt]=b,LS[b]=cnt,Link(tr[b],tr[cnt]);
ans=Dep(tr[root],tr[cnt]);
}
inline void splay(int u,int op,bool del)
{
if(u==root) {
if(op==1&&del){
S.erase(S.begin());
Cut(tr[u],tr[RS[u]]);
root=RS[u];Fa[root]=RS[u]=0;
}
else if(op==2&&del){
S.erase(--S.end());
Cut(tr[u],tr[LS[u]]);
root=LS[u];Fa[root]=LS[u]=0;
}
ans=1;return;
}
node* p=tr[u];
ans=Dep(tr[root],p);
register int v=Fa[u];
if(op==1){
LS[v]=RS[u];Fa[u]=0;
if(RS[u]) Cut(tr[u],tr[RS[u]]),Link(tr[v],tr[RS[u]]),Fa[RS[u]]=v,RS[u]=0;
Cut(tr[u],tr[v]);
if(!del){Link(tr[u],tr[root]);Fa[root]=u;RS[u]=root;root=u;}
else S.erase(*S.begin());
}
else{
RS[v]=LS[u];Fa[u]=0;
if(LS[u]) Cut(tr[u],tr[LS[u]]),Link(tr[v],tr[LS[u]]),Fa[LS[u]]=v,RS[u]=0;
Cut(tr[u],tr[v]);
if(!del){Link(tr[u],tr[root]);Fa[root]=u;LS[u]=root;root=u;}
else S.erase(*(--S.end()));
}
}
int main()
{
m=read();
register int op;
for(register int i=1;i<=m;i++){
op=read();
if(op==1) Add(read());
else if(op==2) splay((*S.begin()).se,1,0);
else if(op==3) splay((*(--S.end())).se,2,0);
else if(op==4) splay((*S.begin()).se,1,1);
else if(op==5) splay((*(--S.end())).se,2,1);
printf("%d\n",ans);
}
}