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

题目链接:hdu 1890 Robotic Sort

题意:

给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次。

题解:

典型的splay区间翻转+删点。

我们把数据排序,然后记录一下每个数原来的位置,然后splay建树的时候用原来的位置来对应,这样val[i].second就直接是这个数在splay中的那个节点。

(当然你也可以普通建树,然后手动记录位置)。

然后我们把要找的那个数对应的节点旋转到根,然后根左边的size+i就是当前数的答案,然后翻转一下前面的数,再删除根。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4
 5 const int N=1e5+7;
 6 int n,a[N],size[N],ch[N][2],f[N],tot,root;bool rev[N];
 7 pair<int,int>val[N];
 8
 9 void rev1(int x){if(!x)return;swap(ch[x][0],ch[x][1]);rev[x]^=1;}
10
11 void pb(int x){
12     if(rev[x]){
13         rev1(ch[x][0]);
14         rev1(ch[x][1]);
15         rev[x]=0;
16     }
17 }
18
19 void up(int x){
20     size[x]=1;
21     if(ch[x][0])size[x]+=size[ch[x][0]];
22     if(ch[x][1])size[x]+=size[ch[x][1]];
23 }
24
25 void rotate(int x){
26     int y=f[x],w=ch[y][1]==x;
27     ch[y][w]=ch[x][w^1];
28     if(ch[x][w^1])f[ch[x][w^1]]=y;
29     if(f[y]){
30         int z=f[y];
31         if(ch[z][0]==y)ch[z][0]=x;
32         if(ch[z][1]==y)ch[z][1]=x;
33     }
34     f[x]=f[y];ch[x][w^1]=y;f[y]=x;up(y);
35 }
36
37 void splay(int x,int w){
38     int s=1,i=x,y;a[1]=x;
39     while(f[i])a[++s]=i=f[i];
40     while(s)pb(a[s--]);
41     while(f[x]!=w){
42         y=f[x];
43         if(f[y]!=w){if((ch[f[y]][0]==y)^(ch[y][0]==x))rotate(x);else rotate(y);}
44         rotate(x);
45     }
46     if(!w)root=x;
47     up(x);
48 }
49
50 void newnode(int &r,int fa,int k)
51 {
52     r=k,f[r]=fa,rev[r]=0,ch[r][0]=ch[r][1]=0;
53 }
54
55 void build(int &x,int l,int r,int fa){
56     int mid=(l+r)>>1;
57     newnode(x,fa,mid);
58     if(l<mid)build(ch[x][0],l,mid-1,x);
59     if(r>mid)build(ch[x][1],mid+1,r,x);
60     up(x);
61     return;
62 }
63
64 int getmax(int x)
65 {
66     pb(x);
67     while(ch[x][1])x=ch[x][1],pb(x);
68     return x;
69 }
70
71 void delroot()
72 {
73     if(ch[root][0])
74     {
75         int m=getmax(ch[root][0]);
76         splay(m,root);
77         ch[m][1]=ch[root][1];
78         f[ch[root][1]]=m;
79         root=m,f[m]=0,up(m);
80     }else root=ch[root][1],f[root]=0;
81 }
82
83 int main(){
84     while(scanf("%d",&n),n)
85     {
86         F(i,1,n)scanf("%d",&val[i].first),val[i].second=i;
87         sort(val+1,val+1+n),build(root,1,n,0);
88         F(i,1,n-1)
89         {
90             splay(val[i].second,0);
91             rev1(ch[root][0]);
92             printf("%d ",i+size[ch[root][0]]);
93             delroot();
94         }
95         printf("%d\n",n);
96     }
97     return 0;
98 }

时间: 2024-10-20 22:03:52

hdu 1890 Robotic Sort(splay 区间反转+删点)的相关文章

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 Robotic Sort 伸展树的区间反转与延迟标记

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

HDU 1890 Robotic Sort

题意: 将一列数字排序  排序规则是  每次找到最小值的位置loc  将1~loc所有数字颠倒  然后删掉第一位  直到排好序  排序要求是稳定的 思路: 这题要做的是  寻找区间最小值位置  翻转区间  的操作  因此可以想到用splay 只需要每个节点记录一个small  就可以实现找到最小值位置 翻转区间操作就是将splay的超级头转到最上面使之成为根  再把loc转到根下面  这时根的右儿子的左儿子就是需要翻转的区间  用一个rev延迟更新  然后将loc转到最上面是指成为根  删掉根

数据结构(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下传标记.

算法模板——splay区间反转 2

实现功能:同splay区间反转 1(基于BZOJ3223 文艺平衡树) 这次改用了一个全新的模板(HansBug:琢磨了我大半天啊有木有),大大简化了程序,同时对于splay的功能也有所完善 这里面没有像一般二叉排序树那样子用一个参量进行排序,而是直接以中序遍历来构建了一个普通的二叉树(当然也可以把每个点的中序遍历排名视作参量),然后插入的时候就是指定位置插入(这个就比较像是文本插入了) 总之得到了较大的提升,代码优美程度也提高不少 1 var 2 i,j,k,l,m,n,head,tot,ll

【bzoj1552/3506】[Cerc2007]robotic sort splay翻转,区间最值

[bzoj1552/3506][Cerc2007]robotic sort Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000.第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. Output 输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,(1 < = Pi < = N),Pi表示第i次操作前第i小的物品所在的位置. 注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]