HDU 1890 Robotic Sort [平衡树splay 区间翻转]

5 篇文章 0 订阅

题意:给出n个数的数组,按照要求排序,每次找到最小的那个数的位置,然后翻转i~pos(i是第i次查找最小的数)

题解:用splay维护区间最小值,val存实际数的大小,用位置为键值建立splay

AC代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define keytree ch[ch[root][1]][0]  
#define L(x) ch[x][0]  
#define R(x) ch[x][1]
#define N 100010
int ch[N][2],pre[N],cnt[N],size[N],val[N],small[N],rev[N],key[N];
int tot,root;
int a[N],n;
void newnode(int &u,int fa,int w,int KEY)
{
	u=++tot;
	ch[u][0]=ch[u][1]=rev[u]=0;
	pre[u]=fa;size[u]=1;
	val[u]=small[u]=w;
	key[u]=KEY;
}
void up(int u)
{
	size[u]=1+size[L(u)]+size[R(u)];
	small[u]=min(val[u],min(small[L(u)],small[R(u)]));
}
void down(int u)
{
	if(rev[u])
	{
		if(L(u))rev[L(u)]^=1;
		if(R(u))rev[R(u)]^=1;
		swap(L(u),R(u));
		rev[u]=0;
	}
}
void rotate(int u,int kind)//kind表示u在fa的哪一边
{
	int fa=pre[u];
	down(fa);down(u);
	ch[fa][kind]=ch[u][!kind];
	pre[ch[u][!kind]]=fa;
	if(pre[fa])ch[pre[fa]][ch[pre[fa]][1]==fa]=u;
	pre[u]=pre[fa];
	ch[u][!kind]=fa;
	pre[fa]=u;
	up(fa);up(u);
}
void splay(int u,int goal)
{
	int fa,kind;
	down(u);
	while(pre[u]!=goal)
	{
		if(pre[pre[u]]==goal)
		{
			down(pre[u]);down(u);
			rotate(u,R(pre[u])==u);
		}
		else 
		{
			fa=pre[u];
			down(pre[u]);down(fa);down(u);
			kind=R(pre[fa])==fa;
			if(ch[fa][kind]!=u)//不在同一侧 
			{
				rotate(u,!kind);
				rotate(u,kind);
			}
			else 
			{
				rotate(fa,kind);
				rotate(u,kind);
			}
		}
	}
	up(u);
	if(goal==0)root=u;
}
int getkth(int u,int k)//第k个键值的点的编号 
{
    down(u);
    int s=size[L(u)]+1;
    if(s==k) return u;
    if(s>k) return getkth(L(u),k);
    else return getkth(R(u),k-s);
}  
int find(int u,int x)//查找键值为x的点的编号 
{                    // 有反转标记时不可用
	down(u);
	if(key[u]==x)return u;
	if(key[u]>x)
	{
		if(!L(u))return -1;
		return find(L(u),x);
	}
	if(key[u]<x)
	{
		if(!R(u))return -1;
		return find(R(u),x);
	}
}
int getpre(int u)
{
    down(u);u=L(u);down(u);
    while(R(u))
    {
        u=R(u);
        down(u);
    }
    return u;
}
int getnext(int u)
{
	down(u);u=R(u);down(u);
	while(L(u))
	{
		u=L(u);
		down(u);
	}
	return u;
}
void del(int x)//删除编号为x的节点 
{
	if(size[root]==1)    
    {    
        root=0;    
        return ;    
    }    
    if(cnt[x]>1)      
    {      
        cnt[x]--;      
        return ;      
    }      
    splay(x,0);      
    if(L(root))      
    {      
        if(!R(root))    
        {    
            pre[L(root)]=0;    
            root=L(root);    
            return ;    
        }    
        int p=getpre(x);      
        splay(p,root);      
        R(p)=R(root);      
        pre[R(root)]=p;      
        root=p;      
        pre[p]=0;      
        up(root);      
    }      
    else      
    {      
        root=R(root);      
        pre[root]=0;      
    }
}
void build(int &u,int l,int r,int fa)//按pos为键值
{                        //val为数的大小 a存数的大小
    if(l>r)return ;
    int mid=(l+r)>>1;
    newnode(u,fa,a[mid],mid);
    build(L(u),l,mid-1,u);
    build(R(u),mid+1,r,u);  
    up(u);
}
void init()  
{
    root=tot=0;
    L(root)=R(root)=pre[root]=size[root]=rev[root]=0;
    val[root]=small[root]=N;  
    newnode(root,0,N,0);
    newnode(R(root),root,N,N);  
    build(keytree,1,n,R(root));
    up(R(root));  
    up(root);  
}
int getmin(int u,int x)//得到区间最小值的相对位置 
{
    down(u);
    if(val[u]==x) return 1+size[L(u)];
    if(small[L(u)]==x) return getmin(L(u),x);
    if(small[R(u)]==x) return size[L(u)]+1+getmin(R(u),x);
}
//--------------------------------------------------基本操作 

struct input  
{  
    int val,id;  
    bool operator<(const input fa) const  
    {  
        if(val==fa.val) return id<fa.id;  
        return val<fa.val;  
    }  
}fzc[N];
 
int main()  
{  
    int i,loc;  
    while(~scanf("%d",&n))  
    {  
        if(!n) break;  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d",&fzc[i].val);  
            fzc[i].id=i;  
        }  
        sort(fzc+1,fzc+n+1);  
        for(i=1;i<=n;i++) a[fzc[i].id]=i;  
        init();
        for(i=1;i<n;i++)  
        {  
            loc=getmin(root,i);
            printf("%d ",loc+i-2);
            splay(getkth(root,1),0);
            splay(getkth(root,loc),root); 
            rev[keytree]^=1;
            splay(getkth(root,loc),0);
            del(root);  
        }  
        printf("%d\n",n);  
    }  
    return 0;  
}  






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值