hdu 1890 Robotic Sort(Splay)

本文介绍使用Splay树解决一个涉及反转区间的编程问题。该问题要求找到经过一系列区间反转操作后,当前最小值所在的位置。文章详细阐述了解决方案的思路,包括如何利用Splay树的特性进行高效的操作,并探讨了rotate与zigzag操作的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

机器人可以每次反转一个区间,要把当前最小的放在最前面。问他反转前,那个数在第几号位置。


思路:

可以知道Splay的左子树就是在他左边的数的个数,所以我们直接用他们的初始位置建树。

然后用num排序。这时可以用从小到大的顺序取出他们在数组中的位置。

把目标放在根节点。

然后找他的左子树的个数+i,然后删除根节点。

之前遇到一个思维上的问题,也是lcm提出来的。既然会反转,那么反转后的位置就变了呀。

比如

3

2 3 1

他们sort以后变成1 2 3.

此时找1,初始位置是3,反转之后变成1 3 2,然后删除节点1,变成 3 2

然后再找2,初始位置是1,但是此时1号位置是3 而不是2了。

后来想了一想,Splay的存放是放在一个静态数组,我们反转只是反转他的ch[x][0-1]。但是他自身存放的位置是不会变的。

所以只管去除数组中的第id号元素就可以了。


还有一个大问题!!!为什么这题用rotate会超时,用zigzag就不会啊。二者的区别是什么啊。也是看了爱酱的博客才发现的。。。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define inf 0x3f3f3f3f
#define maxn 122222
#define keyTree (ch[ch[root][1]][0])

using namespace std;
typedef long long LL;
int S[maxn],que[maxn],ch[maxn][2],pre[maxn],siz[maxn];
int root,top1,top2;

int rev[maxn];
struct node
{
    int num,id;
    bool operator <(const node &cmp)const
    {
        if(num!=cmp.num)return num<cmp.num;
        return id<cmp.id;
    }
}a[maxn];

void Treaval(int x)
{
    if(x)
    {
        Treaval(ch[x][0]);
        printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,rev = %2d \n",x,ch[x][0],ch[x][1],pre[x],siz[x],rev[x]);
        Treaval(ch[x][1]);
    }
}
void debug()
{
    printf("root=%d\n",root);
    Treaval(root);
}
void New(int &x,int PRE,int v)
{
    x=v;
    ch[x][0]=ch[x][1]=0;
    siz[x]=1;
    pre[x]=PRE;
    /*special*/
    rev[x]=0;
}
void pushup(int x)/*special*/
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void pushdown(int x)/*special*/
{
    if(rev[x])
    {
        rev[ch[x][0]]^=1;
        rev[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
        rev[x]=0;
    }
}
void build(int &x,int s,int e,int f)
{
    if(s>e)return;
    int mid=(s+e)>>1;

    New(x,f,mid);

    if(s<mid)build(ch[x][0],s,mid-1,x);
    if(e>mid)build(ch[x][1],mid+1,e,x);
    pushup(x);
}

inline void zig(int x){//左旋
    int y=pre[x], z=pre[y];
    ch[y][1]=ch[x][0]; pre[ch[x][0]]=y;
    ch[x][0]=y; pre[y]=x;
    pre[x]=z;
    if(z) ch[z][ch[z][1]==y]=x;
    pushup(y);
}
inline void zag(int x){//右旋
    int y=pre[x], z=pre[y];
    ch[y][0]=ch[x][1]; pre[ch[x][1]]=y;
    ch[x][1]=y; pre[y]=x;
    pre[x]=z;
    if(z) ch[z][ch[z][1]==y]=x;
    pushup(y);
}
inline void zigzig(int x){
    int y=pre[x], z=pre[y], fz=pre[z];
    ch[z][1]=ch[y][0]; pre[ch[y][0]]=z;
    ch[y][1]=ch[x][0]; pre[ch[x][0]]=y;
    pre[z]=y; ch[y][0]=z;
    pre[y]=x; ch[x][0]=y;
    pre[x]=fz;
    if(fz) ch[fz][ch[fz][1]==z]=x;
    pushup(z); pushup(y);
}
inline void zagzag(int x){
    int y=pre[x], z=pre[y], fz=pre[z];
    ch[z][0]=ch[y][1]; pre[ch[y][1]]=z;
    ch[y][0]=ch[x][1]; pre[ch[x][1]]=y;
    pre[z]=y; ch[y][1]=z;
    pre[y]=x; ch[x][1]=y;
    pre[x]=fz;
    if(fz) ch[fz][ch[fz][1]==z]=x;
    pushup(z); pushup(y);
}
inline void zigzag(int x){
    int y=pre[x], z=pre[y], fz=pre[z];
    ch[y][1]=ch[x][0]; pre[ch[x][0]]=y;
    ch[z][0]=ch[x][1]; pre[ch[x][1]]=z;
    pre[y]=pre[z]=x;
    ch[x][0]=y; ch[x][1]=z;
    pre[x]=fz;
    if(fz) ch[fz][ch[fz][1]==z]=x;
    pushup(z); pushup(y);
}
inline void zagzig(int x){
    int y=pre[x], z=pre[y], fz=pre[z];
    ch[y][0]=ch[x][1]; pre[ch[x][1]]=y;
    ch[z][1]=ch[x][0]; pre[ch[x][0]]=z;
    pre[y]=pre[z]=x;
    ch[x][1]=y; ch[x][0]=z;
    pre[x]=fz;
    if(fz) ch[fz][ch[fz][1]==z]=x;
    pushup(z); pushup(y);
}
void Splay(int x, int goal){
    int y, z;
    pushdown(x);
    while(pre[x]!=goal){
        if(pre[pre[x]]==goal){
            y=pre[x]; pushdown(y); pushdown(x);
            if(ch[y][1]==x) zig(x);
            else zag(x);
        }
        else{
            y=pre[x]; z=pre[y];
            pushdown(z); pushdown(y); pushdown(x);
            if(ch[z][1]==y){
                if(ch[y][1]==x) zigzig(x);
                else zagzig(x);
            }
            else{
                if(ch[y][0]==x) zagzag(x);
                else zigzag(x);
            }
        }
    }
    pushup(x);
    if(pre[x]==0) root=x;
}
/*
inline void Rotate(int x,int kind)
{
    int y=pre[x];
    pushdown(y);
    pushdown(x);
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    pre[x]=pre[y];
    if(pre[x])ch[pre[y]][ch[pre[y]][1]==y]=x;

    ch[x][kind]=y;
    pre[y]=x;
    pushup(y);
  
}
void Splay(int x,int goal)
{
    pushdown(x);
    while(pre[x]!=goal)
    {
        if(pre[pre[x]]==goal)
        Rotate(x,ch[pre[x]][0]==x);
        else
        {
            int y=pre[x];
            int kind=ch[pre[y]][0]==y;
            if(ch[y][kind]==x){
                Rotate(x,!kind);
                Rotate(x,kind);
            }
            else {
                Rotate(y,kind);
                Rotate(x,kind);
            }
        }
    }
    pushup(x);
    if(goal==0)root=x;
}
*/

void RorateTo(int k,int goal)
{
    int r=root;
    pushdown(r);
    while(siz[ch[r][0]]!=k)
    {
        if(k<siz[ch[r][0]])
        {
            r=ch[r][0];
        }
        else
        {
            k-=siz[ch[r][0]]+1;
            r=ch[r][1];
        }
        pushdown(r);
    }
    Splay(r,goal);
}

void erase(int x)
{
    int y=pre[x];
    int head=0,tail=0;
    for(que[tail++]=x;head<tail;head++)
    {
        S[top2++]=que[head];
        if(ch[que[head]][0])que[tail++]=ch[que[head]][0];
        if(ch[que[head]][1])que[tail++]=ch[que[head]][1];
    }
    ch[y][ch[y][1]==x]=0;
    pushup(y);
}
void remove()
{
    int r=ch[root][0];
    if(r==0)
    {
        root=ch[root][1];
        pre[root]=0;
    }
    else {
        pushdown(r);
        while(ch[r][1])
        {
            r=ch[r][1];
            pushdown(r);
        }
        Splay(r,root);

        ch[r][1]=ch[root][1];
        pre[ch[root][1]]=r;
        root=r;
        pre[root]=0;
        pushup(root);

        //erase(tmp);
    }
}

void init(int n)/*special*/
{
    root=top1=top2=0;
    ch[0][0]=ch[0][1]=siz[0]=pre[0]=0;

    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].num);
        a[i].id=i;
    }
    sort(a+1,a+n+1);
    build(root,1,n,0);
}

int main()
{
    int n,m;
    while(scanf("%d",&n)!=EOF && n)
    {
        init(n);
        //debug();
        for(int i=1;i<n;i++)
        {
            //printf("id = %d \n",a[i].id);
            Splay(a[i].id,0);
            rev[ch[root][0]]^=1;
           // debug();
            printf("%d ",siz[ch[root][0]]+i);

            remove();
        }
        printf("%d\n",n);
    }
    return 0;
}
/*
6
3 4 5 1 6 2
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值