Splay Tree

Posted chasedeath

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Splay Tree相关的知识,希望对你有一定的参考价值。

\(Splay Tree\)

\(Splay\)是一种非常诡异的数据结构

核心:二叉搜索树

优化:复杂度均摊\(O(nlog n)\)

优化操作:Splay操作

在刚学\(Splay\)时不建议看它的势能分析,因为并没有什么卵用

引入

二叉搜索树(\(BST,Binary Search Tree\)):

核心性质:左儿子小于自己,右儿子大于自己的一棵二叉树

缺陷:对于不同序列树高会呈现$log?n - n $

\(rotate\)操作

核心:保持BST的大小关系,改变父子关系的一种操作

技术图片

一个正常的BST局部

由父子关系得到 \(c<x<b<y<a<z\)

rotate后

技术图片

可以看到上面的关系依然成立,并且x变成了y的父亲

这样的rotate操作其实取决于被rotate的节点x是y的左儿子还是右儿子,但是两种情况对称,写起来就是

void rotate(int u)
    int f=fa[u],ff=fa[fa[u]],d=son[f][0]==u?0:1,df=son[ff][0]==f?0:1;
    son[ff][df]=u;
    son[f][d]=son[u][!d];
    fa[son[u][!d]]=f;
    son[u][!d]=f;
    fa[u]=ff,fa[f]=u;

\[ \ \]

\[ \ \]

\(Splay\)操作

经典的Splay操作有很多分类讨论,这里我们介绍一种精简一点的版本

Splay(u,to),将\(u\)旋转到\(to\)节点的儿子

并且途中经过的链链长减半(特别的,当\(to\)\(0\)时,即旋转到根)

void Splay(int u,int to)
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(fa[fa[u]]!=to) 
            if((son[f][0]==u)^(son[ff][0]==f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(to==0) rt=u;

\(u\)的祖父不是\(to\)时,考虑两种情况:你与你父亲的作为儿子方向相同和不同(作成图后,可以看到是之字形和一字形)

相同时,如果我们直接多次\(rotate(u)\),会将原来那条\(u\)\(ff\)的链保留,也就是说,仍然存在存在原来链长,所以我们先\(rotate(f)\),就解决了

另一种就直接两次\(rotate(u)\)即可

\[ \ \]

\[ \ \]

\[ \ \]

\(Splay Tree\)基础操作介绍

事实上\(Splay\)相比起其他平衡树做起一些奇怪的操作要方便的多,反正干什么你都直接\(Splay\)就是了

\(Insert\)操作

插入一个权值为x的点,保证没有重复

void Insert(int x)
    int u=rt;
    if(!u) 
        rt=++cnt,val[rt]=x;
        return;
    
    while(son[u][x>val[u]]) u=son[u][x>val[u]];
    son[u][x>val[u]]=++cnt,val[cnt]=x;
    Splay(cnt,0);

注意最后的\(Splay\)操作保证了复杂度

Find_Next操作

插叙一个节点\(x\)的前驱和后继

int Find_Next(int x,int d)
    Splay(x,0);
    int u=son[x][d];
    if(!u) return -1;//不存在
    while(son[u][!d]) u=son[u][!d];
    Splay(u,0);//很关键
    return u;

\(Delete\)操作

将节点编号为\(x\)的点删除

void Del(int x)
    Splay(x,0);
    if(!son[x][0]) 
        rt=son[x][1];
        fa[rt]=0;
        return;
    //如果没有前驱,直接删除
    int u=son[x][0];
    while(son[u][1]) u=son[u][1];//找到x的前驱
    //将前驱Splay到x后,前驱一定是左子树中最大的,它没有右儿子,所以直接将右儿子接上去就可以了
    Splay(u,x);
    son[u][1]=son[x][1];
    fa[son[x][1]]=u;
    rt=u;

如果觉得我的代码有问题,请尽快联系我

\[ \ \]

\[ \ \]

\(Splay\)使用的一些注意事项

1.\(Splay\)的本质依然只是一个\(BST\),所以\(BST\)能干的事它都能干

2.\(Splay\)常数大概是11倍左右,但是跑不满(\(LCT\)是跑满的...)

3.\(Splay\)不建议与其他数据结构嵌套

4.100000以上的数据使用\(Splay\)要小心

5.\(Splay\)操作的不同实现可能对常数有着很大影响

学了一些基本操作,我们搞搞模板题

T1 营业额统计

经典裸题,题意求\(a[1]+\sum _i=2^i<=n min_j=1^j<i\ abs(a[i]-a[j]) \\)

插入,求前驱和后继即可(我为什么不写set...)

注意学习一个新的数据结构时要有耐心,慢慢调...

#include<bits/stdc++.h>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=1e5+10,INF=1e9+10;

int n,m;
int rt,fa[N],son[N][2],sz[N],val[N],c[N],cnt;
void Up(int u)
    sz[u]+=sz[son[u][0]]+sz[son[u][1]];

void rotate(int u)
    int f=fa[u],ff=fa[fa[u]],d=son[f][0]==u?0:1,df=son[ff][0]==f?0:1;
    son[ff][df]=u;
    son[f][d]=son[u][!d];
    fa[son[u][!d]]=f;
    son[u][!d]=f;
    fa[u]=ff,fa[f]=u;
    Up(f),Up(u);
    Up(ff);


void Splay(int u,int to)
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(fa[fa[u]]!=to) 
            if((son[f][0]==u)^(son[ff][0]==f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(to==0) rt=u;


void Find(int x)
    int u=rt;
    while(son[u][x>val[u]]&&val[u]!=x) u=son[u][x>val[u]];
    Splay(u,0);


//0 pre 1 nxt
int Find_Next(int x,int k)
    Find(x);
    if(val[rt]<=x&&!k) return val[rt];
    if(val[rt]>=x&&k) return val[rt];
    int v=son[rt][k];
    if(!v) return INF;
    while(son[v][!k]) v=son[v][!k];
    return val[v];


void Insert(int x)
    if(!rt) 
        rt=++cnt;
        son[cnt][0]=son[cnt][1]=0,c[cnt]=1,sz[cnt]=1;val[cnt]=x;
        return;
    
    Find(x);
    if(val[rt]==x) 
        c[rt]++;
        return; 
    
    int u=rt;
    while(son[u][x>val[u]]) u=son[u][x>val[u]];
    son[u][x>val[u]]=++cnt;
    fa[cnt]=u,son[cnt][0]=son[cnt][1]=0,c[cnt]=1,sz[cnt]=1;val[cnt]=x;
    Splay(cnt,0);



int main()
    ll ans=0;
    rep(i,1,n=rd()) 
        int x=rd();
        if(i==1) ans+=x;
        else 
            int pre=Find_Next(x,0);
            int nxt=Find_Next(x,1);
            ans+=min(abs(pre-x),abs(nxt-x));
        
        Insert(x);
    
    printf("%lld\n",ans);



\[ \ \]

T2 郁闷的出纳员

这题不需要区间操作

插入整体标记,第k大查询

查询第k大操作需要我们存储一个\(size\)值,\(cnt\)表示重复出现的次数

注意在\(Splay\)的时候要\(Up\)

第一次打第k大查询很有可能挂,注意每次\(while\)下去都必须\(Splay\)上来

这个删除操作比较奇怪,建议自己实现一下

void Up(int u)
    if(!u) return;
    sz[u]=sz[son[u][0]]+sz[son[u][1]];
#include<bits/stdc++.h>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)



char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=1e5+10,INF=2e9+10,P=1e9+7;




int n,lim,d;
int rt,fa[N],son[N][2],sz[N],val[N],c[N],cnt;

void Up(int u) 
    if(!u) return;
    sz[u]=c[u]+sz[son[u][0]]+sz[son[u][1]];


void rotate(int u)
    int f=fa[u],ff=fa[f],d=(son[f][1]==u);
    son[ff][son[ff][1]==f]=u;
    son[f][d]=son[u][!d];
    fa[son[u][!d]]=f;
    son[u][!d]=f;
    fa[f]=u;
    fa[u]=ff;
    Up(f),Up(u),Up(ff);



void Splay(int u,int to)
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if((son[f][1]==u)^(son[ff][1]==f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(!to) rt=u;


void Insert(int x)
    if(!rt) 
        rt=++cnt;
        son[cnt][0]=son[cnt][1]=0,c[cnt]=1,sz[cnt]=1;val[cnt]=x;
        return;
    
    int u=rt;
    while(son[u][x>val[u]] && val[u]!=x) u=son[u][x>val[u]];
    if(val[u]==x) 
        c[u]++;
        sz[u]++;
        Splay(u,0);
        return; 
    
    son[u][x>val[u]]=++cnt;
    fa[cnt]=u,son[cnt][0]=son[cnt][1]=0,c[cnt]=1,sz[cnt]=1;val[cnt]=x;
    Splay(cnt,0);


int ans;
void Del()
    int u=rt;
    while(u)
        if(son[u][0] && val[u]+d<=lim)
            ans+=sz[son[u][0]];
            son[u][0]=0;
        
        if(val[u]+d<lim) 
            ans+=c[u];
            if(u==rt) 
                fa[son[u][1]]=0;
                rt=son[u][1];
                u=son[u][1];
                continue;
             else 
                fa[son[u][1]]=fa[u];
                son[fa[u]][son[fa[u]][1]==u]=son[u][1];
                if(!son[u][1]) 
                    if(fa[u]) Splay(fa[u],0);
                    break;
                
                u=son[u][1];
                continue;
            
        
        if(son[u][0]) u=son[u][0];
        else 
            Splay(u,0);
            break;
        
    


int Quekth(int k) 
    if(sz[rt]<k) return -1;
    int u=rt;
    while(u) 
        if(sz[son[u][1]]>=k) u=son[u][1];
        else 
            k-=sz[son[u][1]];
            if(c[u]>=k) 
                Splay(u,0);
                return val[u]+d;
            
            k-=c[u];
            u=son[u][0];
        
    
    return -1;


char opt[20];

int main()
    n=rd(),lim=rd();
    rep(i,1,n) 
        scanf("%s",opt);
        int x=rd();
        if(opt[0]=='I') 
            if(x<lim) continue;
            x-=d;
            Insert(x);
         else if(opt[0]=='A') 
            d+=x;
         else if(opt[0]=='S') 
            d-=x;
         else if(opt[0]=='F') 
            printf("%d\n",Quekth(x));
        
        Del();
    
    printf("%d\n",ans);




\[ \ \]

\[ \ \]

T3 宠物收养所

插入,查询前驱后继,删除操作

注意答案要取模

#include<bits/stdc++.h>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;

const int N=1e5+10,INF=2e9+10,P=1e9+7;
int n,d;
int rt,fa[N],son[N][2],val[N],c[N],cnt;
void rotate(int u)
    int f=fa[u],ff=fa[f],d=(son[f][1]==u);
    son[ff][son[ff][1]==f]=u;
    son[f][d]=son[u][!d];
    fa[son[u][!d]]=f;
    son[u][!d]=f;
    fa[f]=u;
    fa[u]=ff;


void Splay(int u,int to)
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if((son[f][1]==u)^(son[ff][1]==f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(!to) rt=u;


void Insert(int x)
    if(!rt) 
        rt=++cnt;
        son[cnt][0]=son[cnt][1]=0,c[cnt]=1;val[cnt]=x;
        return;
    
    int u=rt;
    while(son[u][x>val[u]] && val[u]!=x) u=son[u][x>val[u]];
    if(val[u]==x) 
        c[u]++;
        Splay(u,0);
        return; 
    
    son[u][x>val[u]]=++cnt;
    fa[cnt]=u,son[cnt][0]=son[cnt][1]=0,c[cnt]=1;val[cnt]=x;
    Splay(cnt,0);


ll ans;
void Find(int x) 
    int u=rt;
    while(val[u]!=x && son[u][x>val[u]]) u=son[u][x>val[u]];
    Splay(u,0);


int Find_Next(int x,int k)
    Find(x);
    if(val[rt]==x||((val[rt]<x)^k)) return rt;
    int u=son[rt][k];
    while(u && son[u][!k]) u=son[u][!k];
    return u;


void Del(int x)
    c[x]--;
    if(c[x]) return;
    int u=son[x][0],f=fa[x];
    if(!u) 
        fa[son[x][1]]=f;
        son[f][son[f][1]==x]=son[x][1];
        if(x==rt) rt=son[x][1];
        return;
    
    while(son[u][1]) u=son[u][1];
    Splay(u,x);
    son[u][1]=son[x][1];
    fa[son[x][1]]=u;
    fa[u]=f;
    son[f][son[f][1]==x]=u;
    if(x==rt) rt=u;

int main()
    n=rd();
    rep(i,1,n) 
        int k=rd(),x=rd();
        if(!rt||k==d) 
            Insert(x);
            d=k;
            continue;
        
        int pre=Find_Next(x,0),nxt=Find_Next(x,1);
        if(!pre || (nxt && val[nxt]-x<x-val[pre])) 
            ans+=val[nxt]-x;
            Del(nxt);
         else 
            ans+=x-val[pre];
            Del(pre);
        
    
    printf("%lld\n",ans%1000000);




写到这里,我们对于\(Splay\)有了一些基础认识,可以来学习一些新的操作了

\(Splay\)区间更新,区间翻转

ll Addmark[N],sum[N];//区间加标记
void Down(int u)
    if(!u) return;
    Addmark[son[u][0]]+=Addmark[u];
    Addmark[son[u][1]]+=Addmark[u];
    sum[son[u][0]]+=sz[son[u][0]]*Addmark[u];
    sum[son[u][1]]+=sz[son[u][1]]*Addmark[u];

我们先来学习经典的\(Down\)操作。。

\(Splay\)上的\(Down\)要稍微注意一下,有两种情况是必须要\(Down\)下去的

1.父子关系发生改变时(即\(rotate\)时)

2.查询节点权值时

再算上\(Up\)操作,我的\(Splay\)函数会变成这样

void rotate(int u) 
    int f=fa[u],ff=fa[f],d=(son[f][1]==u),df=(son[ff][1]==f);
    Down(ff),Down(f),Down(u);
    son[ff][df]=u,fa[u]=ff;
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    son[u][!d]=f,fa[f]=u;
    Up(f),Up(u),Up(ff);


void Splay(int u,int to)
    Down(u);
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f]; 
        if((son[f][1]==u)^(son[ff][1]==f)) rotate(u);
        else rotate(f);
    
    if(!to) rt=u;

(但是经过严谨推导后,其实我们可以发现一些\(Up\)\(Down\)是没有必要的,但是我们先打暴力嘛)

关于如何区间修改

\(l-1 \ Splay\)到根,再将\(r+1 \ Splay\)到根下面,这样的话,我们要求的区间就会汇集在子树\(son[son[rt][1]][0]\)

对于边界问题,当然可以打特判,不过建立两个哨兵会方便一些


void Upd(int l,int r,int x)
    if(l==1&&r==n) 
        sum[rt]+=1ll*x*sz[rt];
        t[rt]+=x;
        val[rt]+=x;
        return;
    
    if(l>1) Splay(l-1,0);
    if(r<n) 
        Splay(r+1,l-1);
        sum[son[r+1][0]]+=x*sz[son[r+1][0]];
        val[son[r+1][0]]+=x;
        t[son[r+1][0]]+=x;
        Splay(son[r+1][0],0);
        return;
    
    sum[son[rt][1]]+=sz[son[rt][1]];
    t[son[rt][1]]+=x;
    val[son[rt][1]]+=x;
    Splay(son[rt][1],0);

这个是打了特判的版本

翻转操作也类似,就不再赘述了

来我们做一道\(Splay\)(线段树)裸题

T4 A Simple Problem with Integers

由于这份代码是我第一次打的(太傻帽了),不建议参考,对拍还是可以的

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<iostream>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=1e5+10,INF=2e9+10,P=1e9+7;

int n,m;
int rt,fa[N],son[N][2],sz[N];
ll sum[N],val[N],t[N];

void Show()
    puts("Now Show The Tree");
    cout<<"root="<<rt<<endl;
    rep(i,1,n) 
        if(son[i][0]) cout<<i<<' '<<son[i][0]<<endl;
        if(son[i][1]) cout<<i<<' '<<son[i][1]<<endl;
    
    rep(i,1,n) cout<<fa[i]<<' '<<val[i]<<' '<<sum[i]<<' '<<t[i]<<' '<<sz[i]<<endl;



void Up(int u)
    if(!u) return;
    sum[u]=val[u]+sum[son[u][1]]+sum[son[u][0]];
    sz[u]=sz[son[u][0]]+sz[son[u][1]]+1;


void Down(int u)
    if(!u||!t[u]) return;
    t[son[u][0]]+=t[u];
    t[son[u][1]]+=t[u];
    sum[son[u][0]]+=t[u]*sz[son[u][0]];
    sum[son[u][1]]+=t[u]*sz[son[u][1]];
    val[son[u][0]]+=t[u];
    val[son[u][1]]+=t[u];
    t[u]=0;



void rotate(int u) 
    int f=fa[u],ff=fa[f],d=(son[f][1]==u),df=(son[ff][1]==f);
    son[ff][df]=u,fa[u]=ff;
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    son[u][!d]=f,fa[f]=u;
    Up(f),Up(u),Up(ff);


void Splay(int u,int to)
    if(!u) return;
    Down(u);
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if((son[f][1]==u)^(son[ff][1]==f)) rotate(f);
            else rotate(u);
        
        rotate(u);
    
    if(!to) rt=u;


int Build(int l,int r)
    if(l>r) return 0;
    int u=(l+r)>>1;
    fa[son[u][0]=Build(l,u-1)]=u;
    fa[son[u][1]=Build(u+1,r)]=u;
    Up(u);
    return u;


char opt[10]; 

void DownNode(int rt,int x)
    int u=rt;
    while(u!=x) 
        Down(u);
        u=son[u][x>u];
    



ll Que(int l,int r)
    if(l==1&&r==n) return sum[rt];
    if(l>1) 
        DownNode(rt,l-1);
        Splay(l-1,0);
    
    if(r<n) 
        DownNode(rt,r+1),Splay(r+1,l-1);
        return sum[son[r+1][0]];
    
    return sum[son[rt][1]];



void Upd(int l,int r,int x)
    if(l==1&&r==n) 
        sum[rt]+=1ll*x*sz[rt];
        t[rt]+=x;
        val[rt]+=x;
        return;
    
    if(l>1) 
        DownNode(rt,l-1);
        Splay(l-1,0);
    
    if(r<n) 
        DownNode(rt,r+1),Splay(r+1,l-1);
        sum[son[r+1][0]]+=x*sz[son[r+1][0]];
        val[son[r+1][0]]+=x;
        t[son[r+1][0]]+=x;
        Splay(son[r+1][0],0);
        return;
    
    sum[son[rt][1]]+=sz[son[rt][1]];
    t[son[rt][1]]+=x;
    val[son[rt][1]]+=x;
    Splay(son[rt][1],0);





int main()
    n=rd(),m=rd();
    rep(i,1,n) val[i]=rd();
    rt=Build(1,n);
    rep(i,1,m) 
        scanf("%s",opt);
        int l=rd(),r=rd();
        if(opt[0]=='Q') printf("%lld\n",Que(l,r));
        else Upd(l,r,rd());
    

技术图片

虽然打得很low但是还是能感觉到两种数据结构的速度差异。。。

其实写到后面也就是一些奇怪的操作的实现罢了,接下来我都是提供一种写法,仅供参考

T5 Robotic Sort

每次找到序列中最小的两个点,然后将一个较小的节点权值赋成无穷大(其实是将上一次完成排序的点删除),将两个点之间的区间翻转

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<iostream>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

#define dir(x) (son[fa[x]][1]==x)


char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=1e5+10,INF=2e9+10,P=1e9+7;

bool be;

int n,m;
int rt,fa[N],son[N][2];
int num[N],t[N];

struct Node
    int x,id;
    bool operator < (const Node __) const
        return x<__.x||(id<__.id&&x==__.x);
    
    bool operator == (const Node __) const
        return x==__.x&&id==__.id;
    
;

Node s[N],a[N];
int sz[N];

void Up(int u)
    if(!u) return;
    s[u]=a[u];
    sz[u]=1;
    if(son[u][0]) s[u]=min(s[u],s[son[u][0]]),sz[u]+=sz[son[u][0]];
    if(son[u][1]) s[u]=min(s[u],s[son[u][1]]),sz[u]+=sz[son[u][1]];


void Down(int u)
    if(!u||!t[u]) return;
    t[son[u][0]]^=1,t[son[u][1]]^=1;
    swap(son[u][0],son[u][1]);
    t[u]=0;


void rotate(int u) 
    int f=fa[u],ff=fa[f],d=dir(u);
    if(ff) son[ff][dir(f)]=u;
    fa[u]=ff;
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    son[u][!d]=f,fa[f]=u;
    Up(f),Up(u),Up(ff);


void Splay(int u,int to)
    if(!u) return;
    Down(u);
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if(dir(u)^dir(f)) rotate(f);
            else rotate(u);
        
        rotate(u);
    
    if(!to) rt=u;


int Build(int l,int r)
    if(l>r) return 0;
    int u=(l+r)>>1;
    t[u]=0;
    fa[son[u][0]=Build(l,u-1)]=u;
    fa[son[u][1]=Build(u+1,r)]=u;
    Up(u);
    return u;





int fir;
int Work()
    int u=rt,res=0,l;
    if(fir) 
        while(1) 
            Down(u);
            if(son[u][0] && s[son[u][0]]==s[u]) 
                u=son[u][0];
                continue;
            
            if(a[u]==s[u]) break;
            u=son[u][1];
        
        s[u]=a[u]=(Node)(int)1e9,u;
        Up(u);
        Splay(u,0);
        l=u;
     else fir=1,l=0;


    u=rt;
    while(1) 
        Down(u);
        if(son[u][0] && s[son[u][0]]==s[u]) 
            u=son[u][0];
            continue;
        
        if(a[u]==s[u]) 
            res+=sz[son[u][0]];
            break;
        
        res+=sz[son[u][0]]+1;
        u=son[u][1];
    
    Splay(u,0);
    Down(u);
    if(son[u][1]) 
        u=son[u][1];
        while(1) 
            Down(u);
            if(son[u][0]) u=son[u][0];
            else break;
        
        if(l) Splay(l,0);
        Splay(u,l);
        t[son[u][0]]^=1;
     else 
        if(l) 
            Splay(l,0);
            t[son[rt][1]]^=1;
         else t[rt]^=1;
    
    return res+1;


bool ed;

int main()
    while(~scanf("%d",&n) && n) 
        rep(i,1,n) a[i]=(Node)rd(),i;
        fa[rt=Build(1,n)]=0;
        fa[0]=0,sz[0]=0;
        s[0]=(Node)(int)1e9,0;
        fir=0;
        rep(i,1,n-1) printf("%d ",Work());
        printf("%d\n",n);
    


\[ \ \]

\[ \ \]

T6 Queue-jumpers

这题涉及到了多种\(Splay\)经典操作

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)

char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=2e5+10;



#define dir(x) (son[fa[x]][1]==x)

int n,m,rt;
int h[N],cnt,c;
int L[N],R[N];
int fa[N],son[N][2],sz[N];

void Show()
    rep(i,1,c) 
        if(son[i][0]) cout<<i<<' '<<son[i][0]<<" 0"<<endl;
        if(son[i][1]) cout<<i<<' '<<son[i][1]<<" 1"<<endl;
    
    rep(i,1,c) cout<<fa[i]<<' '<<sz[i]<<endl;


void Up(int u) 
    if(!u) return;
    sz[u]=R[u]-L[u]+1;
    if(son[u][0]) sz[u]+=sz[son[u][0]];
    if(son[u][1]) sz[u]+=sz[son[u][1]];


void rotate(int u) 
    int f=fa[u],ff=fa[f],d=dir(u);
    if(ff) son[ff][dir(f)]=u; fa[u]=ff; 
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    son[u][!d]=f,fa[f]=u;
    Up(f),Up(u),Up(ff);


void Splay(int u,int to)
    if(!u) return;
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if(dir(u)^dir(f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(!to) rt=u;


int Build(int l,int r)
    if(l>r) return 0;
    int u=(l+r)>>1;
    fa[son[u][0]=Build(l,u-1)]=u;
    fa[son[u][1]=Build(u+1,r)]=u;
    Up(u);
    return u;


int opt[N],optx[N],id[N];
char option[10];

void Top(int x)
    Splay(x,0);
    if(!son[x][0]) return;
    if(!son[x][1])
        swap(son[x][0],son[x][1]);
        return;
     else 
        int u=son[x][1];
        while(son[u][0]) u=son[u][0];
        Splay(u,x);
        fa[son[x][0]]=son[x][1];
        son[son[x][1]][0]=son[x][0];
        Up(son[x][1]);
        son[x][0]=0;
    


int Que(int x)
    Splay(x,0);
    return sz[son[x][0]]+1;


int Rank(int x)
    int u=rt;
    while(u) 
        if(sz[son[u][0]]>=x) 
            u=son[u][0];
            continue;
        
        x-=sz[son[u][0]];
        if(R[u]-L[u]+1>=x) 
            Splay(u,0);
            return L[u]+x-1;
        
        x-=R[u]-L[u]+1;
        u=son[u][1];
    
    return -1;




int main()
    rep(kase,1,rd()) 
        n=rd(),m=rd();
        cnt=0;
        rep(i,1,m) 
            scanf("%s",option);
            optx[i]=rd();
            if(option[0]=='T') opt[i]=0,h[++cnt]=optx[i];
            else if(option[0]=='Q') opt[i]=1,h[++cnt]=optx[i];
            else opt[i]=2;
        
        sort(h+1,h+cnt+1);
        cnt=unique(h+1,h+cnt+1)-h-1;
        int pre=0;
        c=0;
        rep(i,1,cnt) 
            if(h[i]-1>pre) L[++c]=pre+1,R[c]=h[i]-1;
            L[++c]=h[i],R[c]=h[i];
            id[i]=c;
            pre=h[i];
        
        if(n>pre) L[++c]=pre+1,R[c]=n;
        fa[rt=Build(1,c)]=0;fa[0]=sz[0]=0;
        printf("Case %d:\n",kase);
        rep(i,1,m) 
            if(opt[i]==0) Top(id[lower_bound(h+1,h+cnt+1,optx[i])-h]);
            else if(opt[i]==1) printf("%d\n",Que(id[lower_bound(h+1,h+cnt+1,optx[i])-h]));
            else printf("%d\n",Rank(optx[i]));
        
    


\[ \ \]

\[ \ \]

T7 Play with Chain

对于移动链的操作,先把链断开,再找到对应插入位置,再插入

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)

char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=3e5+10;

#define dir(x) (son[fa[x]][1]==x)


int n,m,rt;
int fa[N],son[N][2],sz[N],t[N];

void Show()
    puts("Now Show The Splay Tree");
    cout<<"rt="<<rt<<endl;
    rep(i,1,n) 
        if(son[i][0]) cout<<i<<' '<<son[i][0]<<" 0"<<endl;
        if(son[i][1]) cout<<i<<' '<<son[i][1]<<" 1"<<endl;
    
    rep(i,1,n) cout<<son[i][0]<<' '<<son[i][1]<<' '<<"t="<<t[i]<<' '<<"sz="<<sz[i]<<endl;



void Up(int u) 
    if(!u) return;
    sz[u]=1;
    if(son[u][0]) sz[u]+=sz[son[u][0]];
    if(son[u][1]) sz[u]+=sz[son[u][1]];


void Down(int u)
    if(!u||!t[u]) return;
    swap(son[u][0],son[u][1]);
    t[son[u][0]]^=1;
    t[son[u][1]]^=1;
    t[u]=0;


void rotate(int u)
    int f=fa[u],ff=fa[f],d=dir(u);
    fa[u]=ff; if(ff) son[ff][dir(f)]=u;
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    fa[son[u][!d]=f]=u;
    Up(f),Up(u),Up(ff);


void Splay(int u,int to)
    if(!u) return;
    Down(u);
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if(dir(u)^dir(f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(!to) rt=u;

int Find(int x)
    int u=rt;
    while(1) 
        Down(u);
        if(sz[son[u][0]]>=x) 
            u=son[u][0];
            continue;
        
        x-=sz[son[u][0]];
        if(x==1) break;
        x--;
        u=son[u][1];
    
    return u;



void Move(int l,int r,int c)
    if(l==1&&r==n) return;
    if(l==1) l=0;
    else 
        l--;
        l=Find(l);
        Splay(l,0);
    
    int tmp;
    if(r==n) 
        tmp=son[rt][1];
        son[rt][1]=0;
        Up(rt);
     else 
        r++;
        r=Find(r);
        Splay(r,l);
        tmp=son[r][0];
        son[r][0]=0;
        Up(r),Up(rt);
    
    if(c==0) 
        Splay(Find(1),0);
        fa[son[rt][0]=tmp]=rt;
        Up(rt);
        return;
    
    Splay(Find(c),0);
    if(son[rt][1]) 
        int u;
        Splay(u=Find(c+1),rt);
        son[u][0]=tmp;
        fa[tmp]=u;
        Up(u);
        Up(rt);
     else 
        son[rt][1]=tmp;
        fa[tmp]=rt;
        Up(rt);
    


void Rev(int l,int r)
    if(l==1&&r==n) 
        t[rt]^=1;
        return;
    
    if(l==1) l=0;
    else 
        l--;
        l=Find(l);
        Splay(l,0);
    
    if(r==n) t[son[rt][1]]^=1;
    else 
        r++;
        r=Find(r);
        Splay(r,l);
        t[son[r][0]]^=1;
    


int printcnt;
void Getline(int x)
    Down(x);
    if(son[x][0]) Getline(son[x][0]);
    printf("%d%c",x,++printcnt==n?'\n':' ');
    if(son[x][1]) Getline(son[x][1]);


int Build(int l,int r)
    if(l>r) return 0;
    int u=(l+r)>>1;
    t[u]=0;
    fa[son[u][0]=Build(l,u-1)]=u;
    fa[son[u][1]=Build(u+1,r)]=u;
    Up(u);
    return u;

char opt[10];
int main()
    while(~scanf("%d%d",&n,&m) && ~n ) 
        fa[rt=Build(1,n)]=0;
        fa[0]=sz[0]=0;
        rep(i,1,m) 
            scanf("%s",opt);
            if(opt[0]=='C') 
                int a=rd(),b=rd(),c=rd();
                Move(a,b,c);
             else 
                int l=rd(),r=rd();
                Rev(l,r);
            
        
        printcnt=0;
        Getline(rt);
    

T8 文本编辑器editor0

没错一百万的数据

不过这题数据好像有锅

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)

char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=1<<21;

#define dir(x) (son[fa[x]][1]==x)


int n,rt;
int fa[N],son[N][2],sz[N],t[N];
char s[N],val[N];



void Up(int u) 
    if(!u) return;
    sz[u]=1;
    if(son[u][0]) sz[u]+=sz[son[u][0]];
    if(son[u][1]) sz[u]+=sz[son[u][1]];

void Down(int u)
    if(!u||!t[u]) return;
    swap(son[u][0],son[u][1]);
    t[son[u][0]]^=1;
    t[son[u][1]]^=1;
    t[u]=0;


void Getline(int x)
    Down(x);
    if(son[x][0]) Getline(son[x][0]);
    putchar(val[x]);
    if(son[x][1]) Getline(son[x][1]);

void Show()
    puts("Now Show The Splay Tree");
    rep(i,1,n) 
        if(son[i][0]) cout<<i<<' '<<son[i][0]<<" 0"<<endl;
        if(son[i][1]) cout<<i<<' '<<son[i][1]<<" 1"<<endl;
    
    rep(i,1,n) cout<<fa[i]<<' '<<sz[i]<<' '<<t[i]<<' '<<val[i]<<endl;


void rotate(int u)
    int f=fa[u],ff=fa[f],d=dir(u);
    Down(ff),Down(f),Down(u);
    fa[u]=ff; if(ff) son[ff][dir(f)]=u;
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    fa[son[u][!d]=f]=u;
    Up(f),Up(u),Up(ff);


void Splay(int u,int to)
    if(!u) return;
    Down(u);
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if(dir(u)^dir(f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(!to) rt=u;


char opt[10];

int Build(int l,int r)
    if(l>r) return 0;
    int u=++n,mid=(l+r)>>1;
    val[u]=s[mid];
    fa[son[u][0]=Build(l,mid-1)]=u;
    fa[son[u][1]=Build(mid+1,r)]=u;
    Up(u);
    return u;


int Find(int x) 
    int u=rt;
    while(1) 
        Down(u);
        if(sz[son[u][0]]>=x) 
            u=son[u][0];
            continue;
        
        x-=sz[son[u][0]];
        if(x==1) break;
        x--;
        u=son[u][1];
    
    return u;


int Next(int x,int d)
    Splay(x,0);
    Down(x);
    x=son[x][d];
    Down(x);
    while(son[x][!d])
        x=son[x][!d];
        Down(x);
    
    return x;



int now;
int main()
    rd();
    now=rt=n=1;
    while(~scanf("%s",opt)) 
        if(opt[0]=='I') 
            int c=0,l=rd();
            rep(i,1,l) s[++c]=getchar();
            int t=Build(1,c);
            int nxt=Next(now,1);
            if(nxt) 
                Splay(nxt,0);
                Splay(now,rt);
            
            fa[son[now][1]=t]=now;
            Up(now),Up(rt);
         else if(opt[0]=='M') now=Find(rd()+1);
        else if(opt[0]=='G') 
            int nxt=Next(now,1);
            putchar(val[nxt]);
            if(val[nxt]!='\n') puts("");
         else if(opt[0]=='N') now=Next(now,1);
        else if(opt[0]=='P') now=Next(now,0);
        else if(opt[0]=='D') 
            Splay(now,0);
            int l=rd();
            if(sz[son[now][1]]==l) 
                son[now][1]=0;
                Up(now);
                continue;
            
            int t=Find(sz[son[now][0]]+l+2);
            Splay(t,now);
            son[t][0]=0;
            Up(t),Up(now);
         else 
            Splay(now,0);
            int l=rd();
            if(sz[son[now][1]]==l) 
                t[son[now][1]]^=1;
                continue;
            
            int t=Find(sz[son[now][0]]+l+2);
            Splay(t,now);
            ::t[son[t][0]]^=1;
        
    





\[ \ \]

\[ \ \]

T9 维修数列

不多说了,注意代码常数,如果你写T了,可以看一下我的实现

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cassert>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)

char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=5e5+10,INF=1e9+10;

#define dir(x) (son[fa[x]][1]==x)

int m,rt;
int fa[N],son[N][2];
int Setmark[N],Revmark[N];
int stk[N],top;



struct Node
    ll ls,rs,s,ma;
    int sz;
    Node operator + (const Node x) const 
        Node res;
        res.ls=max(ls,s+x.ls);
        res.rs=max(x.rs,x.s+rs);
        res.s=s+x.s;
        res.ma=max(max(ma,x.ma),rs+x.ls);
        res.sz=sz+x.sz;
        return res;
    
    void operator = (const int x) 
        s=sz*x;
        ls=rs=ma=max(x,sz*x);
    
s[N],val[N];


void Up(int u)
    if(!u) return;
    if(son[u][0]) s[u]=s[son[u][0]]+val[u];
    else s[u]=val[u];
    if(son[u][1]) s[u]=s[u]+s[son[u][1]];


void Down(int u)
    if(!u) return;
    if(Setmark[u]!=INF) 
        if(son[u][0]) 
            Setmark[son[u][0]]=Setmark[u];
            Revmark[son[u][0]]=0;
            s[son[u][0]]=Setmark[u];
            val[son[u][0]]=Setmark[u];
        
        if(son[u][1]) 
            Setmark[son[u][1]]=Setmark[u];
            Revmark[son[u][0]]=0;
            s[son[u][1]]=Setmark[u];
            val[son[u][1]]=Setmark[u];
        
        Setmark[u]=INF;
    
    if(Revmark[u]) 
        if(son[u][0]) 
            Revmark[son[u][0]]^=1;
            swap(s[son[u][0]].ls,s[son[u][0]].rs);
        
        if(son[u][1]) 
            Revmark[son[u][1]]^=1;
            swap(s[son[u][1]].ls,s[son[u][1]].rs);
        
        swap(son[u][0],son[u][1]);
        Up(u);
        Revmark[u]=0;
    


void rotate(int u)
    int f=fa[u],ff=fa[f],d=dir(u);
    Down(ff),Down(f),Down(u);
    fa[u]=ff; if(ff) son[ff][dir(f)]=u;
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    fa[f]=u,son[u][!d]=f;
    Up(f),Up(u),Up(ff);


void Splay(int u,int to)
    Down(u);
    while(fa[u]!=to) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if(dir(u)^dir(f)) rotate(u);
            else rotate(f);
        
        rotate(u);
    
    if(!to) rt=u;


int a[N],tot;
int Build(int l,int r)
    if(l>r) return 0;
    int mid=(l+r)>>1,u=stk[top--];
    val[u].sz=1;val[u]=a[mid];
    Setmark[u]=INF;Revmark[u]=0;
    fa[son[u][0]=Build(l,mid-1)]=u;
    fa[son[u][1]=Build(mid+1,r)]=u;
    Up(u);
    return u;


int Find(int x) 
    int u=rt;
    while(1) 
        Down(u);
        if(s[son[u][0]].sz>=x)  u=son[u][0]; continue; 
        if((x-=s[son[u][0]].sz)==1) break;
        x--,u=son[u][1];
    
    return u;


void Insert(int p)
    p++;
    Splay(Find(p),0);
    Splay(Find(p+1),rt);
    fa[son[son[rt][1]][0]=Build(1,tot)]=son[rt][1];
    Up(son[rt][1]),Up(rt);


queue <int> que;
void Del(int l,int r)
    r+=2;
    Splay(Find(l),0);
    Splay(Find(r),rt);
    que.push(son[son[rt][1]][0]);
    while(!que.empty()) 
        int u=que.front(); que.pop();
        stk[++top]=u;
        if(son[u][0]) que.push(son[u][0]);
        if(son[u][1]) que.push(son[u][1]);
    
    son[son[rt][1]][0]=0;
    Up(son[rt][1]),Up(rt);


void Set(int l,int r,int x)
    r+=2;
    Splay(Find(l),0);
    Splay(Find(r),rt);
    int t=son[son[rt][1]][0];
    Revmark[t]=0,Setmark[t]=x;
    s[t]=x,val[t]=x;
    Up(son[rt][1]),Up(rt);


void Reverse(int l,int r)
    r+=2;
    Splay(Find(l),0);
    Splay(Find(r),rt);
    int t=son[son[rt][1]][0];
    if(Setmark[t]!=INF) return;
    Revmark[t]^=1;
    swap(s[t].ls,s[t].rs);
    Up(son[rt][1]),Up(rt);


ll GetSum(int l,int r)
    r+=2;
    Splay(Find(l),0);
    Splay(Find(r),rt);
    return s[son[son[rt][1]][0]].s;


ll GetAns()
    return s[rt].ma;

char opt[20];


int main() 
    tot=rd(),m=rd();
    drep(i,N-1,1) stk[++top]=i;
    tot+=2;
    rep(i,2,tot-1) a[i]=rd();
    a[tot]=a[1]=-INF;
    fa[rt=Build(1,tot)]=0;
    rep(tttt,1,m) 
        scanf("%s",opt);
        if(opt[0]=='I') 
            int p=rd();
            rep(i,1,tot=rd()) a[i]=rd();
            Insert(p);
         else if(opt[0]=='D') 
            int l=rd(),r=rd()+l-1;
            Del(l,r);
         else if(opt[0]=='M'&&opt[2]=='K') 
            int l=rd(),r=rd()+l-1;
            Set(l,r,rd());
         else if(opt[0]=='R') 
            int l=rd(),r=rd()+l-1;
            Reverse(l,r);
         else if(opt[0]=='G') 
            int l=rd(),r=rd()+l-1;
            printf("%lld\n",GetSum(l,r));
         else printf("%lld\n",GetAns());
    

\[ \ \]

\[ \ \]

T10 Box

毕竟是压轴的题,还是有一定思维难度的

(其实就是一个LCT裸题嘛)

做法是,将每棵树化成括号序列,建立\(Splay\)森林

一个子树就是一段区间,然后就可以直接整个区间移动了

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cassert>
#include<cstring>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

char IO;
int rd()
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;


const int N=1e5+10,INF=1e9+10;

#define dir(x) (son[fa[x]][1]==x)

bool be;

int n,m;
int fa[N],son[N][2];

struct Edge
    int to,nxt;
e[N<<1];
int head[N],ecnt,ind[N];
void AddEdge(int u,int v)
    e[++ecnt]=(Edge)v,head[u];
    head[u]=ecnt;
    ind[v]++;


int line[N],lc;
void dfs(int u)
    line[++lc]=u;
    for(int i=head[u];i;i=e[i].nxt) 
        int v=e[i].to;
        dfs(v);
    
    line[++lc]=u+n;

void rotate(int u)
    int f=fa[u],ff=fa[f],d=dir(u);
    fa[u]=ff; if(ff) son[ff][dir(f)]=u;
    son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
    son[u][!d]=f,fa[f]=u;

void Splay(int u,int to)
    while(fa[u]!=to && fa[u]) 
        int f=fa[u],ff=fa[f];
        if(ff!=to) 
            if(dir(f)^dir(u)) rotate(u);
            else rotate(f);
        
        rotate(u);
    

int Build(int l,int r)
    if(l>r) return 0;
    int mid=(l+r)>>1,u=line[mid];
    fa[son[u][0]=Build(l,mid-1)]=u;
    fa[son[u][1]=Build(mid+1,r)]=u;
    return u;


int GetRoot(int x)
    Splay(x,0);
    while(son[x][0]) x=son[x][0];
    Splay(x,0);
    return x;


void Move(int x,int to)
    Splay(x,0);
    if(son[x][0]) 
        int l=son[x][0];
        while(son[l][1]) l=son[l][1];
        Splay(l,0);
        Splay(x+n,l);
        int r=x+n;
        r=son[r][1];
        while(son[r][0]) r=son[r][0];
        Splay(r,l);
        if(!to) 
            fa[son[r][0]]=0;
            son[r][0]=0;
            return ;
        
        x=son[r][0],son[r][0]=0;
        fa[x]=0;
        Splay(to,0);
        if(fa[x]) 
            Splay(x,0);
            son[r][0]=x;fa[x]=r;
            return;
        
        int t=son[to][1];
        while(son[t][0]) t=son[t][0];
        Splay(t,to);
        son[t][0]=x;
        fa[x]=t;
     else // A whole tree
        if(!to) return;
        Splay(to,0);
        if(fa[x]) return;
        int t=son[to][1];
        while(son[t][0]) t=son[t][0];
        Splay(t,to);
        son[t][0]=x;
        fa[x]=t;
    


bool ed;
int fir;
char opt[10];
int main()
    //cout<<&ed-&be<<endl;
    while(~scanf("%d",&n)) 
        if(fir) puts("");
        else fir=1;
        memset(ind,0,sizeof ind);memset(head,0,sizeof head),ecnt=0;
        lc=0;
        rep(i,1,n) 
            int x=rd();
            if(x) AddEdge(x,i);
        
        rep(i,1,n) if(!ind[i]) 
            int t=lc+1;
            dfs(i);
            fa[Build(t,lc)]=0;
        
        fa[0]=0;
        rep(i,1,m=rd()) 
            scanf("%s",opt);
            if(opt[0]=='Q') printf("%d\n",GetRoot(rd()));
            else 
                int x=rd(),to=rd();
                if(x^to) Move(x,to);
            
        
    

以上是关于Splay Tree的主要内容,如果未能解决你的问题,请参考以下文章

SPLAY or SPALY ?

「Splay」指针版与数组版模板

在洛谷3369 Treap模板题 中发现的Splay详解

splay学习小记[未完结]

Splay树(21.8.1)

Splay入门