Description
Input
Output
Sample Input
Sample Output
题解Here!
inline void turn(int rt,int k){ int x=a[rt].f,y=a[x].f; pushdown(x);pushdown(rt); a[x].son[k^1]=a[rt].son[k]; if(a[rt].son[k])a[a[rt].son[k]].f=x; a[rt].f=y; if(y)a[y].son[a[y].son[1]==x]=rt; a[x].f=rt; a[rt].son[k]=x; pushup(x);pushup(rt);}void spaly(int rt,int ancestry){ while(a[rt].f!=ancestry)turn(rt,a[a[rt].f].son[0]==rt); if(ancestry==0)root=rt;}
这样你就有20分暴力了。。。
然后,慢慢分析单旋的性质。
1. 插入操作:
我们会发现这样一个事实:
一个节点的插入所经过的$Spaly$路径,必然经过这个节点的$key$值在$Spaly$上的前驱与后继!
并且新插入的节点一定在前驱与后继中深度更深的节点的儿子节点上!
那就好办了,我们只要找到$key$的前驱与后继就可以了。
怎么找?
拿出了$Spaly$的原型——双旋的$Splay$!
$Splay$的复杂度是$O(\log_2n)$的,当然可以胜任。
于是只要$Splay$上的节点与$Spaly$的节点的编号一一对应就可以了。
为了方便,我们让它们相同。
找到$key$的前驱与后继了,就挂在前驱的右儿子,或者是后继的左儿子上,看那个深度更深就是了。
这个操作完美解决。
2. 单旋最小值:
我们知道,$Spaly$与$Splay$的最小值一定没有左儿子!
我们可以手动模拟一下$Spaly$上的最小值单旋到根的过程。(尽量把$Spaly$的深度画成3或者4,方便寻找规律)
我们又发现了一个事实:
当最小值单旋到根之后,最小值的深度为1(这不废话嘛)。
此时最小值仅有右子树。
但右子树即为除了最小值的$Spaly$!
并且形态只改变了一点:原来最小值的右子树 / 接到了 / 原来最小值的父亲的左子树 / 上!(“/”表停顿)
而且深度还没有变!
听得比较绕。。。
但是这个性质让我们可以用$Splay$维护某节点在$Spaly$上的深度!
把最小值的深度改为$1$不用多说。
之后呢?
先将最小值的右子树打上$-1$的标记(以后会抵消),再在$Splay$上旋转到根,然后对其右子树打上$+1$标记(抵消了前面的$-1$标记)。
那,$Spaly$的形态怎么维护呢?
把最小值与其父亲的父子关系断开,最小值与其右儿子的父子关系断开,将最小值的右儿子与最小值的父亲连上父子关系,最小值的右儿子挂在最小值的父亲的左儿子上。
再将最小值与原来$Spaly$的根节点连上父子关系,最小值为父亲。
然后每次旋转的时候不要忘了$pushdown$一下。。。
然后就没了。。。
3. 单旋最大值:
这个跟操作2差不多吧,省略。。
4. 单旋删除最小值:
题目都说了先执行操作2。。。
然后按照题目所说断开最小值(现在的根节点)与原来的根节点的父子关系,之后把根节点换成原来的根节点,并打上$+1$的标记。
然后就没了啊。。。
5. 单旋删除最大值:
同操作4,这里就省略了。
呼~终于解决了!
总复杂度应该是$Splay$的复杂度,即均摊$O(n\log_2n)$。
这题真的是毒瘤。。。
真心膜拜考场上写出来的那些大佬。。。
反正本蒟蒻顶多20分。。。
因为就算想出来了,也没有时间敲+调试了。。。
调试代码毁天灭地,鄙人把它们删掉了。
附上删掉毁天灭地的调试代码之后仍然毁天灭地的代码:
#include#include #include #define MAXN 100010using namespace std;int n,m=0,size=1,root=0,head;struct Splay{ int f,s,son[2]; int v,c,key;}a[MAXN];struct Spaly{ int f,son[2];}b[MAXN];inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w;}inline void clean(int rt){ a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].s=a[rt].v=a[rt].c=0; b[rt].f=b[rt].son[0]=b[rt].son[1]=0;}inline void pushup(int rt){ if(!rt)return; a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;}inline void pushdown(int rt){ if(!rt||!a[rt].c)return; if(a[rt].son[0]){ a[a[rt].son[0]].c+=a[rt].c; a[a[rt].son[0]].v+=a[rt].c; } if(a[rt].son[1]){ a[a[rt].son[1]].c+=a[rt].c; a[a[rt].son[1]].v+=a[rt].c; } a[rt].c=0;}inline void turn(int rt,int k){ int x=a[rt].f,y=a[x].f; pushdown(x);pushdown(rt); a[x].son[k^1]=a[rt].son[k]; if(a[rt].son[k])a[a[rt].son[k]].f=x; a[rt].f=y; if(y)a[y].son[a[y].son[1]==x]=rt; a[x].f=rt; a[rt].son[k]=x; pushup(x);pushup(rt);}void splay(int rt,int ancestry){ while(a[rt].f!=ancestry){ int x=a[rt].f,y=a[x].f; pushdown(y);pushdown(x);pushdown(rt); if(y==ancestry)turn(rt,a[x].son[0]==rt); else{ int k=a[y].son[0]==x; if(a[x].son[k]==rt){turn(rt,k^1);turn(rt,k);} else{turn(x,k);turn(rt,k);} } } if(ancestry==0)root=rt;}inline int newnode(int fa,int key){ int rt=size++; if(fa)a[fa].son[a[fa].key a[y].s+1){ k-=a[y].s+1; rt=a[rt].son[1]; } else if(k<=a[y].s)rt=y; else return rt; }}int front_next(int rt,int x,int k){ find(rt,x); rt=root; if((a[rt].key>x&&k)||(a[rt].key a[next].v)fa=front; else fa=next; a[rt].v=a[fa].v+1; b[rt].f=fa; if(fa)b[fa].son[a[fa].key