title
题面巨长,不想贴了,不然这篇 \(blog\) 就都成题面了
analysis
\(Orz\) yyb 。
这题的题目让你维护一个 \(splay\) ,正解就肯定不是 \(splay\) 了,要不然就有点不正常了(刚才去翻了一下洛谷题解,好像真的有大佬是写了 \(splay\) 的,有点打脸)。
反正我选择用 \(LCT\) 来维护这棵 \(splay\) 了(默认 \(LCT\) 都会写了)。
下面说下五个操作:
第一个操作,一个新建入的节点要么接在前驱的右儿子,要么接在后继的左儿子,那么,搞一个 \(set\) 求一求前驱后继,很容易证明前驱的右儿子和后继的左儿子一定有且仅有一个为空,直接接上去就行了。
剩下的四个操作,最大/最小值旋到根,就是把它的儿子给父亲,然后 \(root\) 直接变成它的儿子,它变成 \(root\) ,于是每次的操作之和两个点有关,在 \(LCT\) 中维护点在 \(spaly\) 上的父子关系。(在删除操作的时候,要先判断这个点已经是 \(root\) 的情况的)
code
写的巨长,\(258\) 行
#include<bits/stdc++.h>
const int maxn=2e5+10;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
namespace LCT
{
int ch[maxn][2];
typedef int iarr[maxn];
iarr fa,siz,Stack;
bool r[maxn];
inline bool nroot(int x)
{
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
inline void pushup(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
inline void rever(int x)
{
std::swap(ch[x][0],ch[x][1]);
r[x]^=1;
}
inline void pushdown(int x)
{
if (r[x])
{
if (ch[x][0]) rever(ch[x][0]);
if (ch[x][1]) rever(ch[x][1]);
r[x]=0;
}
}
inline void rotate(int x)//一次旋转
{
int y=fa[x],z=fa[y],k=ch[y][1]==x,w=ch[x][!k];
if (nroot(y)) ch[z][ch[z][1]==y]=x;
ch[x][!k]=y,ch[y][k]=w;//额外注意if(nroot(y))语句,此处不判断会引起致命错误(与普通Splay的区别2)
if (w) fa[w]=y;
fa[y]=x,fa[x]=z;
pushup(y);
}
inline void splay(int x)
{
int y=x,z=0;
Stack[++z]=y;
while (nroot(y)) Stack[++z]=y=fa[y];
while (z) pushdown(Stack[z--]);
while (nroot(x))
{
y=fa[x], z=fa[y];
if (nroot(y)) rotate((ch[y][0]==x)^(ch[z][0]==y) ? x : y);
rotate(x);
}
pushup(x);
}
inline void access(int x)
{
for (int y=0; x; y=x, x=fa[x]) splay(x), ch[x][1]=y, pushup(x);
}
inline void makeroot(int x)
{
access(x);splay(x);rever(x);
}
inline int findroot(int x)
{
access(x);splay(x);
while (ch[x][0]) pushdown(x), x=ch[x][0];
splay(x);
return x;
}
inline void split(int x,int y)
{
makeroot(x);
access(y), splay(y);
}
inline void link(int x,int y)
{
makeroot(x);
if (findroot(y)^x) fa[x]=y;
}
inline void cut(int x,int y)
{
makeroot(x);
if (findroot(y)==x && fa[y]==x && !ch[y][0])
{
fa[y]=ch[x][1]=0;
pushup(x);
}
}
}
using LCT::siz;
using LCT::split;
using LCT::link;
using LCT::cut;
int tot,root;
int ls[maxn],rs[maxn],fa[maxn];
std::map<int,int>M;
std::set<int>s;
inline void insert(int x)
{
int now=++tot;
M[x]=now;
if (s.empty())
{
s.insert(x);
root=now;
write(1,'\n');
return ;
}
std::set<int>::iterator it=s.upper_bound(x);
if (it==s.end() || ls[M[*it]])
{
--it;
int k=M[*it];
link(now,k), rs[k]=now, fa[now]=k;
}
else
{
int k=M[*it];
link(now,k), ls[k]=now,fa[now]=k;
}
s.insert(x);
split(now,root);
write(siz[root],'\n');
}
inline void Splay_min()
{
int x=M[*s.begin()];
if (root==x) { write(1,'\n'); return ; }
split(x,root);
write(siz[root],'\n');
cut(x,fa[x]);
if (rs[x]) cut(x,rs[x]);
link(x,root);
if (rs[x]) link(fa[x],rs[x]);
ls[fa[x]]=rs[x];
if (rs[x]) fa[rs[x]]=fa[x];
fa[x]=0, fa[root]=x, rs[x]=root;
root=x;
}
inline void Splay_max()
{
int x=M[*--s.end()];
if (root==x) { write(1,'\n'); return ; }
split(x,root);
write(siz[root],'\n');
cut(x,fa[x]);
if (ls[x]) cut(x,ls[x]);
link(x,root);
if (ls[x]) link(ls[x],fa[x]);
rs[fa[x]]=ls[x];
if (ls[x]) fa[ls[x]]=fa[x];
fa[x]=0, fa[root]=x, ls[x]=root;
root=x;
}
inline void Del_min()
{
int x=M[*s.begin()];
if (root==x)
{
write(1,'\n');
if (rs[x]) cut(x,rs[x]);
fa[rs[x]]=0, root=rs[x];
s.erase(s.begin());
return ;
}
split(x,root);
write(siz[root],'\n');
cut(x,fa[x]);
if (rs[x]) cut(x,rs[x]);
if (rs[x]) link(fa[x],rs[x]);
ls[fa[x]]=rs[x];
if (rs[x]) fa[rs[x]]=fa[x];
s.erase(s.begin());
}
inline void Del_max()
{
int x=M[*--s.end()];
if (root==x)
{
write(1,'\n');
if (ls[x]) cut(x,ls[x]);
fa[ls[x]]=0, root=ls[x];
s.erase(--s.end());
return ;
}
split(x,root);
write(siz[root],'\n');
cut(x,fa[x]);
if (ls[x]) cut(x,ls[x]);
if (ls[x]) link(ls[x],fa[x]);
rs[fa[x]]=ls[x];
if (ls[x]) fa[ls[x]]=fa[x];
s.erase(--s.end());
}
int main()
{
int n;read(n);
while (n--)
{
int opt,x;read(opt);
if (opt==1) read(x), insert(x);
else if (opt==2) Splay_min();
else if (opt==3) Splay_max();
else if (opt==4) Del_min();
else Del_max();
}
IO::flush();
return 0;
}