title
BZOJ 4825
LUOGU 3721
題面巨長,不想貼了,不然這篇 \(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;
}
轉載于:https://www.cnblogs.com/G-hsm/p/11447867.html