题目大意
你需要维护一个spaly,这个数据结构在将节点旋转到根只会一直单旋自己。
有
q
个操作,你需要对每一个操作都输出其时间代价,操作有如下几种:
∙
单旋最大值:将spaly中的最大值单旋到根,代价为单旋之前该节点的深度。
∙
单旋删除最小值:在单旋最小值的基础上,删掉根节点(显然没有左子树),代价同单旋最小值。
∙
单旋删除最大值:在单旋最大值的基础上,删掉根节点(显然没有右子树),代价同单旋最大值。
保证所有关键字互不相同。
1≤q≤105
题目分析
考虑使用link cut tree来维护树的形态,同时记录一下每个点的真实左右儿子和父亲。使用set可以很快地查询一个点的前驱和后继。插入时显然是插在前驱和后继两个点中深度较大的那个下面。单旋操作的话可以发现它其实只影响了很少几个点,其它点都不变,就瞎link一下cut一下就好了。深度的话可以直接用lct操作求。
时间复杂度
O(nlogn)
。
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <stack>
#include <set>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
int buf[30];
void write(int x)
{
if (x<0) putchar('-'),x=-x;
for (;x;x/=10) buf[++buf[0]]=x%10;
if (!buf[0]) buf[++buf[0]]=0;
for (;buf[0];putchar('0'+buf[buf[0]--]));
}
const int N=100050;
int val[N];
struct cmp{bool operator()(const int& x,const int& y)const{return val[x]<val[y];}};
set<int,cmp> BST;
int q,tot;
namespace link_cut_tree
{
int fa[N],size[N],par[N],Fa[N],left[N],right[N];
bool mark[N];
int son[N][2];
stack<int> st;
int root;
bool side(int x){return son[fa[x]][1]==x;}
void init(){size[0]=fa[0]=par[0]=0;}
void update(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;}
void R(int x){swap(son[x][0],son[x][1]),mark[x]^=1;}
void clear(int x)
{
if (mark[x])
{
if (son[x][0]) R(son[x][0]);
if (son[x][1]) R(son[x][1]);
mark[x]=0;
}
}
void rotate(int x)
{
int y=fa[x];bool s=side(x);
if (fa[y]) son[fa[y]][side(y)]=x;
if (son[x][s^1]) fa[son[x][s^1]]=y;
son[y][s]=son[x][s^1],son[x][s^1]=y;
fa[x]=fa[y],fa[y]=x;
if (par[y]) par[x]=par[y],par[y]=0;
update(y),update(x);
}
void pushdown(int x,int y)
{
for (;x!=y;st.push(x),x=fa[x]);
for (;!st.empty();clear(st.top()),st.pop());
}
void splay(int x,int y)
{
for (pushdown(x,y);fa[x]!=y;rotate(x))
if (fa[fa[x]]!=y)
if (side(x)==side(fa[x])) rotate(fa[x]);
else rotate(x);
}
int access(int x)
{
int nxt=0;
for (;x;update(nxt=x),x=par[x])
{
splay(x,0);
if (son[x][1]) par[son[x][1]]=x,fa[son[x][1]]=0;
if (nxt) par[nxt]=0,fa[nxt]=x;
son[x][1]=nxt;
}
return nxt;
}
void makeroot(int x){R(access(x));}
void link(int x,int y)
{
makeroot(x),access(x),splay(x,0);
par[x]=y,access(x);
}
void cut(int x,int y)
{
makeroot(x),access(y),splay(y,0);
fa[x]=par[y]=son[y][0]=0,update(y);
}
int add(int x)
{
val[++tot]=x,x=tot;
set<int,cmp>::iterator it=BST.insert(tot).first;
if (!root) update(root=x);
else
{
int p=0,q=0,d1=0,d2=0;
if (it!=BST.begin()) p=*(--it),makeroot(root),access(p),splay(p,0),d1=size[p],++it;
++it;
if (it!=BST.end()) q=*it,makeroot(root),access(q),splay(q,0),d2=size[q];
--it;
if (d1>d2) right[p]=x,Fa[x]=p,update(x),link(p,x);
else left[q]=x,Fa[x]=q,update(x),link(q,x);
}
return makeroot(root),access(x),splay(x,0),size[x];
}
int getmin(bool del)
{
int x=*BST.begin(),ret,y;
if (del) BST.erase(x);
makeroot(root),access(x),splay(x,0),ret=size[x],y=right[x];
if (x==root)
{
if (del&&y) Fa[y]=0,cut(x,y),root=y;
}
else
{
cut(x,Fa[x]),left[Fa[y]]=y,update(x);
if (y) cut(x,y),Fa[y]=Fa[x],left[Fa[y]]=y,link(y,Fa[x]);
Fa[x]=0;
if (!del)
{
splay(root,0),Fa[root]=x,right[x]=root,update(root);
link(x,root),root=x;
}
}
return ret;
}
int getmax(bool del)
{
int x=*BST.rbegin(),ret,y;
if (del) BST.erase(x);
makeroot(root),access(x),splay(x,0),ret=size[x],y=left[x];
if (x==root)
{
if (del&&y) Fa[y]=0,cut(x,y),root=y;
}
else
{
cut(x,Fa[x]),right[Fa[y]]=y,update(x);
if (y) cut(x,y),Fa[y]=Fa[x],right[Fa[y]]=y,link(y,Fa[x]);
Fa[x]=0;
if (!del)
{
splay(root,0),Fa[root]=x,left[x]=root,update(root);
link(x,root),root=x;
}
}
return ret;
}
};
int main()
{
freopen("splay.in","r",stdin),freopen("splay.out","w",stdout);
for (q=read();q--;)
{
int opt=read();
if (opt==1) write(link_cut_tree::add(read())),putchar('\n');
else
{
--opt;
if (opt&1) write(link_cut_tree::getmin(opt==3)),putchar('\n');
else write(link_cut_tree::getmax(opt==4)),putchar('\n');
}
}
fclose(stdin),fclose(stdout);
return 0;
}