HDU 1890 Robotic Sort

题意:

将一列数字排序  排序规则是  每次找到最小值的位置loc  将1~loc所有数字颠倒  然后删掉第一位  直到排好序  排序要求是稳定的

思路:

这题要做的是  寻找区间最小值位置  翻转区间  的操作  因此可以想到用splay

只需要每个节点记录一个small  就可以实现找到最小值位置

翻转区间操作就是将splay的超级头转到最上面使之成为根  再把loc转到根下面  这时根的右儿子的左儿子就是需要翻转的区间  用一个rev延迟更新  然后将loc转到最上面是指成为根  删掉根  如此循环

注意:

由于翻转区间这种更新会改变树的结构  因此无论是splay的时候还是做任何查找的时候都必须先把rev给down下去!!

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
#define keytree ch[ch[root][1]][0]
#define L(x) ch[x][0]
#define R(x) ch[x][1]
#define N 100010

int n,tot,root;
int a[N],ch[N][2],pre[N],size[N],val[N],small[N],rev[N];

void newnode(int &u,int fa,int w)
{
	u=++tot;
	L(u)=R(u)=0;
	pre[u]=fa;
	size[u]=1;
	small[u]=val[u]=w;
	rev[u]=0;
}

void up(int u)
{
	size[u]=size[L(u)]+size[R(u)]+1;
	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)
{
	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);
}

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,L(pre[u])==u);
        }
		else
		{
			fa=pre[u];
			down(pre[fa]);
			down(fa);
			down(u);
			kind=L(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)
{
	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);
}

void build(int &u,int l,int r,int fa)
{
	if(l>r) return ;
	int mid=(l+r)>>1;
	newnode(u,fa,a[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);
	newnode(R(root),root,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);
}

int getpre(int u)
{
    down(u);
    u=L(u);
    down(u);
    while(R(u))
    {
        u=R(u);
        down(u);
    }
    return u;
}

void remove()
{
    if(L(root))
    {
        int i=getpre(root);
        splay(i,root);
        R(i)=R(root);
        pre[R(root)]=i;
        root=L(root);
        pre[root]=0;
        up(root);
    }
    else
    {
        root=R(root);
        pre[root]=0;
    }
}

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);
            remove();
        }
        printf("%d\n",n);
	}
	return 0;
}

HDU 1890 Robotic Sort

时间: 2024-08-04 22:22:38

HDU 1890 Robotic Sort的相关文章

hdu 1890 Robotic Sort(splay 区间反转+删点)

题目链接:hdu 1890 Robotic Sort 题意: 给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次. 题解: 典型的splay区间翻转+删点. 我们把数据排序,然后记录一下每个数原来的位置,然后splay建树的时候用原来的位置来对应,这样val[i].second就直接是这个数在splay中的那个节点. (当然你也可以普通建树,然后手动记录位置). 然后我们把要找的那个数对应的节点旋转到根,然后根左边的size+i就

HDU 1890 Robotic Sort 伸展树的区间反转与延迟标记

延迟标记像极了线段树,不再多说. 区间反转在树伸展到位之后,也变成了简单的递归交换左右儿子. 愈发感觉到伸展树简直太漂亮了,伸展操作更是诱惑到不行 ,总之数据结构太有魅力了. 比较简单,就直接上模板了. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #in

数据结构(Splay平衡树):HDU 1890 Robotic Sort

Robotic Sort Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3456    Accepted Submission(s): 1493 Problem Description Somewhere deep in the Czech Technical University buildings, there are labora

Splay练习题 [HDU 1890] Robotic Sort

Robotic Sort Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2495    Accepted Submission(s): 1107 Problem Description Somewhere deep in the Czech Technical University buildings, there are labor

HDU 1890 Robotic Sort(splay)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=1890 [题意] 给定一个序列,每次将i..P[i]反转,然后输出P[i],P[i]定义为当前数字i的所在位置.相等的两个数排序后相对位置不变. [思路] 由于相对位置不变,所以可以根据数值与位置重编号. 依旧使用直接定位从上到下旋转至根的splay写法.每次将i结点旋转至根,则答案为左儿子大小+i,然后将i删掉合并左右儿子. 需要注意合并时判断左右儿子是否为空,以及各种pushdown下传标记.

HDU 1890 - Robotic Sort - [splay][区间反转+删除根节点]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description Somewhere deep in the Czech Technical University buildings, there are laboratories for examining

HDU 1890 Robotic Sort (Splay)

题意:将一列数字排序  排序规则是  每次找到最小值的位置loc  将1~loc所有数字颠倒  然后删掉第一位  直到排好序  排序要求是稳定的. 析:直接用splay来维护最小值,然后插入删除即可. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include

HDU 1890 Robotie Sort

Problem Description Somewhere deep in the Czech Technical University buildings, there are laboratories for examining mechanical and electrical properties of various materials. In one of yesterday's presentations, you have seen how was one of the labo

HDU 1890 Splay区间翻转

D - Robotic Sort Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1890 Appoint description:  System Crawler  (2014-11-27) Description Somewhere deep in the Czech Technical University buildings, t