并不对劲的splay
splay和不加任何旋转一定会被卡的二叉搜索树的唯一区别就是每次操作把当前节点旋转到根。
旋转有各种zig、zag的组合方式,感觉很麻烦,并不对劲的人并不想讲。
其实可以找出一些共性将它们合并。设ls(a)=[点a是其父亲的左儿子],son[a][0]=a的左儿子,son[a][1]=a的右儿子,fa[a]=a的父亲。会发现单旋u时,有变动的点只有son[u][ls(u)^1],u,fa[u],fa[fa[u]]。再仔细想想,儿子有变动的有fa[fa[u]](son[fa[fa[u]]][ls(fa[u])]=u)、fa[u](son[fa[u]][ls(u)]=son[u][ls(u)^1])、u(son[u][ls(u)^1]=fa[u]),父亲有变化的是fa[u](fa[fa[u]]=u)、u(fa[u]=fa[fa[u]])、son[u][ls(u)^1](fa[son[u][ls(u)^1]=fa[u])。都有三组,好记(可能吧…)又好写。
而当双旋u时,若u,fa[u],fa[fa[u]]不共线(即ls(u)^ls(fa[u])==1),则先单旋u,再单旋u;反之,则先单旋fa[u],再单旋u。每次旋转如果深度不小于2就双旋,否则单旋。这样写起来就会很容易了。
根据刚刚的旋转方法,可以看出每次被旋转到根的节点至多经历一次单旋。
至于时间复杂度,在刚学splay时就觉得它很不靠谱,因为感觉每次把某个节点旋转到根并不能缩短多少时间。后来发现每次操作总会进行很多次双旋,双旋总能让这个树变的和你想象中不太一样。
至于严格证明什么的,还是交给手健康的人手推吧,这里并不是对劲的splay。
例题:洛谷2286 [HNOI2004]宠物收养场
并不觉得这题有什么好说的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<iomanip> #include<cstdlib> #define maxn 80001 #define inf 1ll<<32 #define mod 1000000 #define ll long long using namespace std; ll read(){ ll x=0,f=1; char ch=getchar(); while(isdigit(ch)==0 && ch!='-')ch=getchar(); if(ch=='-')f=-1; while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } ll n,f; ll ans; typedef struct node { ll son[2],fa;//0左,1右 ll key; }Tree; struct Splay { ll cnt,root; Tree x[maxn]; inline void rot(ll u){ ll fu=x[u].fa,ffu=x[fu].fa,l=(x[fu].son[1]==u),r=l^1; ll l2=(fu==x[ffu].son[1]); x[ffu].son[l2]=u; x[u].fa=ffu; x[fu].fa=u; x[fu].son[l]=x[u].son[r]; x[x[u].son[r]].fa=fu; x[u].son[r]=fu; } inline void splay(ll u,ll k){ while(x[u].fa!=k){ ll fu=x[u].fa,ffu=x[fu].fa; if(ffu!=k){ if((x[ffu].son[0]==x[u].fa)^(x[fu].son[0]==u)) rot(u); else rot(fu); } rot(u); } if(k==0)root=u; } inline void ins(ll k){ ll lk=nxt_no_equ(k,0), rk=nxt_no_equ(k,1); splay(lk,0),splay(rk,lk); x[rk].son[0]=++cnt; x[cnt].fa=rk,x[cnt].son[0]=x[cnt].son[1]=0,x[cnt].key=k; splay(cnt,0); } inline void fnd(ll k){ ll u=root; if(u==0)return; while(x[u].son[k>x[u].key] && k!=x[u].key) u=x[u].son[k>x[u].key]; splay(u,0); } inline ll nxt_no_equ(ll k,ll f){//f==1 bigger fnd(k); ll u=root; if(x[u].key>k && f)return u; if(x[u].key<k && f==0)return u; u=x[u].son[f]; while(x[u].son[f^1])u=x[u].son[f^1]; return u; } inline ll nxt_yes_equ(ll k,ll f){ fnd(k); ll u=root; if(x[u].key>=k && f)return u; if(x[u].key<=k && f==0)return u; u=x[u].son[f]; while(x[u].son[f^1])u=x[u].son[f^1]; return u; } inline void del(ll k){ ll lk=nxt_no_equ(k,0), rk=nxt_no_equ(k,1); splay(lk,0),splay(rk,lk); x[rk].son[0]=0; } void start(){ cnt=0; root=0; ins(inf);ins(-inf); } }t; int main() { n=read(); t.start(); for(ll i=1;i<=n;i++) {// x,f=0 pet , x,f=1 people ll x=read(),y=read(); if(f==0){ t.ins(y); } else{ if(x==(f<0))t.ins(y); else{ ll lt=t.x[t.nxt_no_equ(y,0)].key, rt=t.x[t.nxt_no_equ(y,1)].key, ttt=abs(lt-y)<=abs(rt-y)?lt:rt; ans+=abs(ttt-y); t.del(ttt); } } f+=(x==1)?-1:1; ans%=mod; } cout<<ans%mod; return 0; }