Splay模板

本文详细解析洛谷P3391题目的解题思路,重点介绍翻转操作的实现技巧,通过使用自平衡二叉搜索树进行节点更新和维护,实现了高效的数据结构操作。

题目:https://www.luogu.org/problemnew/show/P3391

主要练习翻转操作;

有好几个地方的顺序写反了,调了好久好久...

整体+1,就可以在翻转时使用左端点-1和右端点+1了;

节点的val是在原数列中的位置,节点所在的树中位置是现在数列的顺序;

所以输出就是中序遍历,输出val。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const MAXN=1e5+5;
int n,m,cnt,root,del_cur,del_pool[MAXN];
struct N{
    int ch[3],fa,val,rev,size;
}t[MAXN];
int newnode()
{
    if(del_cur)
    {
        int x=del_cur;del_cur--;
        return del_pool[x];
    }
    cnt++;
    return cnt;
}
void del(int x)
{
    del_pool[++del_cur]=x;
    t[x].ch[0]=0;t[x].ch[1]=0;t[x].fa=0;t[x].val=0;
    t[x].rev=0;t[x].size=0;
}
void pushup(int x)
{
    t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
}
void pushdown(int x)
{
    if(t[x].rev)
    {
        t[t[x].ch[0]].rev^=1;
        t[t[x].ch[1]].rev^=1;
        swap(t[x].ch[0],t[x].ch[1]);//(顺序)
        t[x].rev=0;
    }
}
void rotate(int x)
{
    int y=t[x].fa,z=t[y].fa;
    int d=t[y].ch[1]==x;
    t[z].ch[t[z].ch[1]==y]=x;t[x].fa=z;
    t[y].ch[d]=t[x].ch[d^1];t[t[x].ch[d^1]].fa=y;
    t[x].ch[d^1]=y;t[y].fa=x;//与上行顺序不能反 
    pushup(y);pushup(x);//顺序 
}
void splay(int x,int goal)
{
    while(t[x].fa!=goal)//while而非if 
    {
        int y=t[x].fa,z=t[y].fa;
        if(z!=goal)
        {
            if((t[y].ch[0]==x)==(t[z].ch[0]==y))rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    pushup(x);
    if(!goal)root=x;
}
void insert(int v)
{
    if(!root)
    {
        root=newnode();
        t[root].val=v;t[root].size=1;
        return;
    }
    int x=root;
    while(1)
    {
        int d=t[x].val<v;
        if(!t[x].ch[d])
        {
            int k=newnode();
            t[x].ch[d]=k;t[k].fa=x;
            t[k].val=v;t[k].size=1;
            splay(k,0);//!
            break;
        }
        x=t[x].ch[d];
    }
}
int Kth(int k)
{
    int u=root;
    while(1)
    {
        pushdown(u);
        if(t[t[u].ch[0]].size+1==k)return u;
        if(t[t[u].ch[0]].size+1>k)u=t[u].ch[0];
        else 
        {
            k-=t[t[u].ch[0]].size+1;
            u=t[u].ch[1];//与上行顺序不能反 
        }
    }
}
void Rev(int L,int R)
{
    int l=Kth(L),r=Kth(R+2);
    splay(l,0);splay(r,l);//r,l而非l,r 
    t[t[r].ch[0]].rev^=1;
}
void print(int x)
{
    pushdown(x);
//    printf("x=%d l=%d r=%d\n",x,t[x].ch[0],t[x].ch[1]);
    if(t[x].ch[0])print(t[x].ch[0]);
    if(t[x].val>1&&t[x].val<=n+1)printf("%d ",t[x].val-1);
    if(t[x].ch[1])print(t[x].ch[1]);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+2;i++)insert(i);//+1
    for(int i=1,l,r;i<=m;i++)
    {
        scanf("%d%d",&l,&r);
        Rev(l,r);
    }
    print(root);
    return 0;
}

 

转载于:https://www.cnblogs.com/Zinn/p/9034182.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值