洛谷P3165 [CQOI2014]排序机械臂

题目描述

为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂。它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序;第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序。

上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序;第二次操作前,第二低的物品在位罝6,于是把第2至6的物品反序...

你的任务便是编写一个程序,确定一个操作序列,即每次操作前第i低的物品所在位置Pi,以便机械臂工作。需要注意的是,如果有高度相同的物品,必须保证排序后它们的相对位置关系与初始时相同。

输入输出格式

输入格式:

第一行包含正整数n,表示需要排序的物品数星。

第二行包含n个空格分隔的整数ai,表示每个物品的高度。

输出格式:

输出一行包含n个空格分隔的整数Pi。

输入输出样例

输入样例#1: 复制

6
3 4 5 1 6 2

输出样例#1: 复制

4 6 4 5 6 6

好变态的题啊。
我们可以发现一个很显然的规律:
第\(i-1\)小的数一定不可能在第\(i\)次查询的区间里
那么我们可以维护一下最小值,对于每次询问,在区间内找到最小值
然后打上标记就好

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=1e5+10;
const int maxn=0x7fffff;
const int INF=0x7fffffff;
#define ls tree[x].ch[0]
#define rs tree[x].ch[1]
inline char nc()
{
    static char buf[MAXN],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    char c=nc();int x=0,f=1;
    while(c<'0'||c>'9'){c=nc();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();}
    return x*f;
}
int n,m;
struct Q
{
    int val,pos;
}a[MAXN];
struct node
{
    int tot,fa,ch[2],mn,mnpos,v;
    bool rev;
}tree[MAXN];
int tot,point;
int root;
int PosL,PosR;
inline void connect(int x,int fa,bool how)
{
    tree[x].fa=fa;
    tree[fa].ch[how]=x;
}
inline void update(int k)
{
    if(!k)  return ;
    tree[k].tot=tree[tree[k].ch[0]].tot+tree[tree[k].ch[1]].tot+1;
    tree[k].mn=tree[k].v; tree[k].mnpos=k;
    if(tree[k].ch[0]&&tree[tree[k].ch[0]].mn<tree[k].mn)    tree[k].mn=tree[tree[k].ch[0]].mn,tree[k].mnpos=tree[tree[k].ch[0]].mnpos;
    if(tree[k].ch[1]&&tree[tree[k].ch[1]].mn<tree[k].mn)    tree[k].mn=tree[tree[k].ch[1]].mn,tree[k].mnpos=tree[tree[k].ch[1]].mnpos;
}
inline int BuildTree(int l,int r)
{
    if(l>r) return 0;
    int mid=(l+r)>>1;
    if(l!=r)
    {
        connect(BuildTree(l,mid-1),mid,0);
        connect(BuildTree(mid+1,r),mid,1);
    }
    tree[mid].rev=0;
    tree[mid].mn=a[mid].val;
    tree[mid].v=a[mid].val;
    tree[mid].mnpos=mid;
    update(mid);
    return mid;
}
inline bool ident(int x)
{
    return tree[tree[x].fa].ch[1]==x;
}
inline void pushdown(int x)
{
    if(tree[x].rev)
    {
        swap(tree[x].ch[0],tree[x].ch[1]);
        tree[tree[x].ch[0]].rev^=1;
        tree[tree[x].ch[1]].rev^=1;
        tree[x].rev=0;
    }
}
inline void rotate(int X)
{
    pushdown(tree[X].fa);pushdown(X);
    int Y=tree[X].fa;
    if(Y==root) root=X;
    int R=tree[Y].fa;
    bool Yson=ident(X);
    bool Rson=ident(Y);
    int B=tree[X].ch[Yson^1];
    connect(B,Y,Yson);
    connect(Y,X,Yson^1);
    connect(X,R,Rson);
    update(Y);update(X);
}
inline void splay(int x,int to)
{
    to=tree[to].fa;
    while(tree[x].fa!=to)
    {
        if(tree[tree[x].fa].fa==to)     rotate(x);
        else if(ident(x)==ident(tree[x].fa)) rotate(tree[x].fa),rotate(x);
        else rotate(x),rotate(x);
    }
    update(x);
}
int find(int x, int rk)
{
    pushdown(x);//标记下传
    if(tree[ls].tot+1==rk) return x;
    else if(tree[ls].tot >= rk) return find(ls, rk);
    else return find(rs, rk-tree[ls].tot-1);
}
const int comp(const Q a,const Q b)
{
    return a.val<b.val||(a.val==b.val&&a.pos<b.pos);
}
const int comp2(const Q a,const Q b)
{
    return a.pos<b.pos;
}
int QueryMin(int l,int r)
{
    int x1=find(root,l);
    int x2=find(root,r+2);
    splay(x1,root);
    splay(x2,tree[x1].ch[1]);
    return tree[ tree[x2].ch[0] ].mnpos;
}
inline void rever(int l,int r)
{
    int x1=find(root,l),x2=find(root,r+2);
    splay(x1,root);splay(x2,tree[x1].ch[1]);
    tree[tree[x2].ch[0]].rev^=1;
}
int main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    int n=read();
    a[1].val=a[n+2].val=INF;
    for(int i=2;i<=n+1;i++) a[i].val=read(),a[i].pos=i;
    sort(a+2,a+n+2,comp);
    for(int i=2;i<=n+1;i++) a[i].val=i-1;
    sort(a+2,a+n+2,comp2);
    //for(int i=1;i<=n+2;i++)   printf("%d ",a[i].pos);printf("\n");
    BuildTree(1,n+2);
    root=(n+3)>>1;
    for(int i=1;i<=n;i++)
    {
        int x=QueryMin(i,n);
        splay(x,root);
        int out=tree[tree[x].ch[0]].tot;
        rever(i,out);
        printf("%d ",out);
    }
}
时间: 2024-10-25 16:40:23

洛谷P3165 [CQOI2014]排序机械臂的相关文章

P3165 [CQOI2014]排序机械臂

P3165 [CQOI2014]排序机械臂 题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序. 上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序:第二次操作前,第二低的物品在位罝6,于是把第2至6的物品反序... 你的任务便是编写一个程序,确定

Luogu P3165 [CQOI2014]排序机械臂

先讲一下和这题一起四倍经验的题: Luogu P4402 [Cerc2007]robotic sort 机械排序 SP2059 CERC07S - Robotic Sort UVA1402 Robotic Sort 这题作为一道十分经典的平衡树维护序列的问题,自然是值得一做的了. 写完翻了下题解发现都是写Splay的dalao,少有的暴力FHQ_Treap党还是用指针实现的. 所以这里略微讲解下数组实现的FHQ_Treap好了,感觉写起来比Splay舒服些. 首先我们要抽象化一下题意:给你\(n

[CQOI2014]排序机械臂

洛谷P3165 [CQOI2014]排序机械臂 https://www.luogu.org/problem/show?pid=3165 题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序. 上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序:第二次

[BZOJ3506] [Cqoi2014] 排序机械臂 (splay)

Description 同OJ1552 Input Output Sample Input Sample Output HINT Source Solution Q:哎不是同一道题吗为什么分两篇博客来写? A:当然是来骗浏览量了233333333,这里还是会放代码的,当然你左转BZOJ1552的题解也行. 1 #include <bits/stdc++.h> 2 using namespace std; 3 struct spaly 4 { 5 int c[2], fa, siz, rev;

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

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

LibreOJ2241 - 「CQOI2014」排序机械臂

Portal Description 给出一个\(n(n\leq10^5)\)个数的序列\(\{a_n\}\),对该序列进行\(n\)次操作.若在第\(i\)次操作前第\(i\)小的数在\(p_i\)位置,则翻转区间\([i,p_i]\).易知\(n\)次操作后序列会变为升序.求出每一次的\(p_i\). Solution splay. 题里的\(a_i\)是会重复的...所以先离散化一波,相同的数按位置排名.然后根据初始位置建一棵splay,每次将\(i\)旋转到根求左子树大小即可,区间翻转用

【BZOJ3506】排序机械臂(Splay)

[BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标记的问题 我只在第K大放会鬼.. 所以在Splay里面也放了一次(和LCT一样的) 然而我每次都把排到了正确位置的元素直接给删掉了... 所以跑的很慢很慢... #include<iostream> #include<cstdio> #include<cstdlib> #i

【BZOJ】【1552】【Cerc2007】robotic sort / 【3506】【CQOI2014】排序机械臂

Splay 离散化+Splay维护序列…… 好吧主要说一下我做这道题遇到的几个错误点: 1.离散化 2.由于找到的这个数的位置一定是大于等于 i 的,所以其实在把它splay到根以后,i 结点只能splay到它的左儿子,而不是右儿子……而且相应的,代表这个区间的应该是c[c[root][0]][1]呃……就是root的左儿子的右儿子= =整个反了一下……好吧不要在意这些细节,我也不知道为什么我突然要反过来写[捂脸熊] 3.进行了修改操作以后一定要立即splay修改的结点!在这题中就是当找到最小结

BZOJ 3506 CQOI 2014 排序机械臂 Splay

题目大意:给出一个序列,给出一种排序方式,模拟这种排序方式排序,并输出每次找到的节点的位置. 思路:它让你做什么你就做什么,无非就是个Reverse,很简单.注意一下排序的时候权值相等的情况就行了. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define INF 0x3f3f3f3f using