BZOJ1552[Cerc2007]robotic sort&BZOJ3506[Cqoi2014]排序机械臂——非旋转treap

题目描述

输入

输入共两行,第一行为一个整数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
 
非旋转treap练习题。题目要求每次找到第i小的Pi并将i~Pi翻转,因为在第i次操作时,前i小的数在最前面不会被翻转,之后也不会被用到。那么我们可以对序列建非旋转treap每次找到最小的,然后删除掉它,再将它原位置之前的部分翻转即可。但发现不能只维护子树最小值,因为有相同值时要选编号小的,也不能有多个最小值优先遍历左子树,因为原先编号小的翻转后可能成了右子树。所以我们先将原序列排个序,按排序后的顺序作为他们新的权值,再按原顺序插入treap,这样每个点的权值就是独一无二的了,直接记录最小值每次查找即可。不要忘记查找时也要下传翻转标记。
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n;
int cnt;
int root;
int x,y,z;
int v[100010];
int s[100010];
int r[100010];
int mn[100010];
int ls[100010];
int rs[100010];
int size[100010];
struct miku
{
    int val;
    int num;
    int rak;
}a[100010];
bool cmp1(miku a,miku b)
{
    if(a.val!=b.val)
    {
        return a.val<b.val;
    }
    return a.num<b.num;
}
bool cmp2(miku a,miku b)
{
    return a.num<b.num;
}
int build(int val)
{
    int rt=++cnt;
    r[rt]=rand();
    v[rt]=val;
    mn[rt]=val;
    size[rt]=1;
    return rt;
}
void rotate(int rt)
{
    swap(ls[rt],rs[rt]);
    s[rt]^=1;
}
void pushup(int rt)
{
    size[rt]=size[ls[rt]]+size[rs[rt]]+1;
    mn[rt]=v[rt];
    if(ls[rt])
    {
        mn[rt]=min(mn[rt],mn[ls[rt]]);
    }
    if(rs[rt])
    {
        mn[rt]=min(mn[rt],mn[rs[rt]]);
    }
}
void pushdown(int rt)
{
    if(s[rt])
    {
        if(ls[rt])
        {
            rotate(ls[rt]);
        }
        if(rs[rt])
        {
            rotate(rs[rt]);
        }
        s[rt]^=1;
    }
}
int merge(int x,int y)
{
    if(!x||!y)
    {
        return x+y;
    }
    pushdown(x);
    pushdown(y);
    if(r[x]<r[y])
    {
        rs[x]=merge(rs[x],y);
        pushup(x);
        return x;
    }
    else
    {
        ls[y]=merge(x,ls[y]);
        pushup(y);
        return y;
    }
}
void split(int rt,int k,int &x,int &y)
{
    if(!rt)
    {
        x=y=0;
        return ;
    }
    pushdown(rt);
    if(size[ls[rt]]<k)
    {
        x=rt;
        split(rs[rt],k-size[ls[rt]]-1,rs[x],y);
    }
    else
    {
        y=rt;
        split(ls[rt],k,x,ls[y]);
    }
    pushup(rt);
}
int rank(int rt)
{
    pushdown(rt);
    int res=v[rt];
    if(ls[rt])
    {
        res=min(res,mn[ls[rt]]);
    }
    if(rs[rt])
    {
        res=min(res,mn[rs[rt]]);
    }
    if(res==mn[ls[rt]])
    {
        return rank(ls[rt]);
    }
    else if(res==v[rt])
    {
        return size[ls[rt]]+1;
    }
    else
    {
        return size[ls[rt]]+1+rank(rs[rt]);
    }
}
int main()
{
    srand(20020419);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].val);
        a[i].num=i;
    }   
    sort(a+1,a+1+n,cmp1);
    for(int i=1;i<=n;i++)
    {
        a[i].rak=i;
    }
    sort(a+1,a+1+n,cmp2);
    for(int i=1;i<=n;i++)
    {
        root=merge(root,build(a[i].rak));
    }
    for(int i=1;i<=n;i++)
    {  
        int ans=rank(root);
        printf("%d",i-1+ans);
        if(i!=n)
        {
            printf(" ");
        }
        split(root,ans-1,x,y);
        split(y,1,y,z);
        rotate(x);
        root=merge(x,z);
    }
}
posted @ 2018-09-22 16:27  The_Virtuoso  阅读(249)  评论(0编辑  收藏  举报