BZOJ 1552: [Cerc2007]robotic sort( splay )

kpm大神说可以用块状链表写...但是我不会...写了个splay....

先离散化 , 然后splay结点加个min维护最小值 , 就可以了...

( ps BZOJ 3506 题意一样 , 双倍经验 )

-----------------------------------------------------------------------

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<iostream>

#define rep( i , n ) for( int i = 0 ; i < n ; ++i )

#define clr( x , c ) memset( x , c , sizeof( x ) )

#define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )

using namespace std;

const int maxn = 100000 + 5;

const int maxnode = 101000;

const int inf = 0x7fffffff;

int n;

struct data {

int v , pos;

bool operator < ( const data &rhs ) const {

return ( v < rhs.v ) || ( v == rhs.v && pos < rhs.pos );

}

};

bool cmp( const data &a , const data &b ) {

return a.pos < b.pos;

}

data A[ maxn ];

struct Node *pt , *null;

struct Node {

Node *ch[ 2 ] , *p;

int mn , val , size;

bool rev;

Node( int v = inf ) {

mn = val = v;

ch[ 0 ] = ch[ 1 ] = null;

rev = 0;

}

inline void setc( Node* c , int d ) {

ch[ d ] = c;

c -> p = this;

}

inline bool d() {

return this == p -> ch[ 1 ];

}

inline void Rev() {

rev ^= 1;

}

inline void upd() {

size = ch[ 0 ] -> size + ch[ 1 ] -> size + 1;

mn = min( val , min( ch[ 0 ] -> mn , ch[ 1 ] -> mn ) );

}

inline void relax() {

if( rev ) {

swap( ch[ 0 ] , ch[ 1 ] );

rep( i , 2 ) if( ch[ i ] != null )

ch[ i ] -> Rev();

rev = 0;

}

}

void* operator new( size_t ) {

return pt++;

}

};

Node NODE[ maxnode ];

Node* root;

Node* build( int l , int r ) {

if( l >= r )

return null;

int m = ( l + r ) >> 1;

Node* t = new Node( A[ m ].v );

t -> setc( build( l , m ) , 0 );

t -> setc( build( m + 1 , r ) , 1 );

t -> upd();

return t;

}

void rot( Node* t ) {

Node* p = t -> p;

p -> relax();

t -> relax();

int d = t -> d();

p -> p -> setc( t , p -> d() );

p -> setc( t -> ch[ ! d ] , d );

t -> setc( p , ! d );

p -> upd();

if( p == root ) root = t;

}

void splay( Node* t , Node* f = null ) {

while( t -> p != f ) {

if( t -> p -> p == f ) rot( t );

else if( t -> d() != t -> p -> d() ) rot( t ) , rot( t );

else rot( t -> p ) , rot( t );

}

t -> upd();

}

Node* select( int k ) {

for( Node* t = root ; ; ) {

t -> relax();

int s = t -> ch[ 0 ] -> size;

if( s == k ) return t;

else if( s < k ) {

k -= s + 1;

t = t -> ch[ 1 ];

} else

t = t -> ch[ 0 ];

}

}

int v;

Node* find( Node* t ) {

t -> relax();

if( t -> val == v ) return t;

else return find( t -> ch[ 0 ] -> mn != v ? t -> ch[ 1 ] : t -> ch[ 0 ] );

}

Node* &get( int l , int r ) {

l-- , r++;

Node* L = select( l );

Node* R = select( r );

splay( L );

splay( R , L );

return R -> ch[ 0 ];

}

void init() {

pt = NODE;

null = new( Node );

null -> size = 0;

root = build( 0 , n + 2 );

root -> p = null;

}

int main() {

freopen( "test.in" , "r" , stdin );

cin >> n;

Rep( i , n ) {

scanf( "%d" , &A[ i ].v );

A[ i ].pos = i;

}

sort( A + 1 , A + n + 1 );

Rep( i , n ) A[ i ].v = i;

sort( A + 1 , A + n + 1 , cmp );

A[ 0 ].v = A[ n + 1 ].v = inf;

init();

Rep( i , n ) {

v = i;

Node* &t = get( i , n );

Node* x = find( t );

splay( x );

int k = x -> ch[ 0 ] -> size;

printf( "%d" , k );

if( i != n ) printf( " " );

x = get( i , k );

x -> Rev();

splay( x );

}

return 0;

}

-----------------------------------------------------------------------

1552: [Cerc2007]robotic sort

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 486  Solved: 203
[Submit][Status][Discuss]

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]反转(单个物品)。

Sample Input

6
3 4 5 1 6 2

Sample Output

4 6 4 5 6 6

HINT

Source

HNOI2009集训Day6

时间: 2024-12-23 13:36:26

BZOJ 1552: [Cerc2007]robotic sort( splay )的相关文章

bzoj 1552: [Cerc2007]robotic sort.

1552: [Cerc2007]robotic sort Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1211  Solved: 463[Submit][Status][Discuss] Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. 第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. Output 输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,Pi表示第i次

1552: [Cerc2007]robotic sort

1552: [Cerc2007]robotic sort Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1205  Solved: 459 Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. 第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. Output 输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,Pi表示第i次操作前第i小的物品所在的位置. 注意:如果第i次操

【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]

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

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

HDU1890 Robotic Sort[splay 序列]

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

BZOJ 1552/1506 [Cerc2007]robotic sort

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1552 [分析] 这题哇!又有翻转操作...每次要输出第几个?是吧... 所以又要用Splay了. 可是这道题有创新的地方,因为又有数值上的有序[取最小值],又有位置上的有序[翻转和求第几个] 可是毕竟最小值的操作会简单很多...所以我们采用的是将位置作为Splay的节点信息. 那么怎么快速得到最小值的位置呢?当然就是常用的push_up了...向上更新就好了. 这里一定要注意题目所说:按

[BZOJ1552][Cerc2007]robotic sort

试题描述 输入 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000.第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. 输出 输出共一行,N个用空格隔开的正整数P1,P2,P3-Pn,Pi表示第i次操作前第i小的物品所在的位置. 注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品). 输入示例 6 3 4 5 1 6 2 输出示例 4 6 4 5 6 6 数据规模及约定 见"输入" 题解 暴力

HDU 1890 Robotic Sort (Splay)

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

[bzoj1552][Cerc2007]robotic sort&amp;&amp;[bzoj3506][Cqoi2014]排序机械臂

非常垃圾的一道平衡树,结果被日了一天.很难受嗷嗷嗷 首先不得不说网上的题解让我这个本来就不熟悉平衡树的彩笔很难受--并不好理解. 还好Sinogi大佬非常的神,一眼就切掉了,而且用更加美妙的解法. 题意在操作时,就是第i次把编号为i-1和编号i的后继分别提到根和根的右儿子,根的右儿子的左子树打上翻转标记. 用外部数组记录原来高度第几大的在平衡树中编号是多少.就可以直接操作了. 注意有相同的高度,离散化时直接按高度第一关键字,编号第二关键字就行了. 还有每次splay要把根到当前节点都pushdo