HYSBZ 3506 排序机械臂

题意:
给定一个长度为N的物品排列和一个可以把一段连续的物品翻转的机械臂,你要通过N次机械臂操作将物品按升序排序,第i次操作必须将第i个物品放在第i个位置上。即在第i次操作中,你需要用机械臂将区间[i,P[i]]翻转(P[i]为该次操作前第i个数的位置)。你在每次操作前需要输出P[i]。
简化版:你需要维护一个序列,支持区间翻转与查询区间最小。
题解:
①由于区间最小实际上每一次就是对应的整个数列的第k小,因此可以直接预处理解决,接下来考虑如何找到这个点,可以直接用一个指针解决,然后就是简单的无旋treap操作:
②给定一个平衡树上节点,求它在当前序列中的下标,首先我们先将这个点到平衡树根节点的标记下传,使用递归解决,然后就直接根据BST的性质查找即可。
③其余的就是按照题意进行区间rotate,这是无旋Treap的简单操作之一,不多赘述。

#pragma GCC optimize (4)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100000+10;
const int Inf=1e9;
typedef long long LL;
int n,A[maxn],num,root;
struct Hash{
        int id,x;
        bool operator<(const Hash &A)const{
                if(A.x==x)return id<A.id;
                return x<A.x;
        }
}Map[maxn];
struct Treap{
        int lch,rch;
        int data,Min,size;
        bool lazy;
        #define L(u) a[u].lch
        #define R(u) a[u].rch
}a[maxn<<1];
typedef pair<int,int> D;
void Init();
void Pushup(int);
void Rotate(int);
void Pushdown(int);
int Build(int,int);
D Split(int,int);
int Merge(int,int);
int GetRank(int);
int main(){
        a[0].Min=Inf;
        Init();
        return 0;
}
void Init(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&A[i]),Map[i].x=A[i],Map[i].id=i;
    sort(Map+1,Map+1+n);
    for(int i=1;i<=n;i++)
        A[Map[i].id]=i;
    root=Build(1,n);
    for(int i=1;i<=n;i++){
        int tmp=GetRank(i);
        printf("%d ",tmp+i-1);
        D y=Split(root,tmp);
        Rotate(y.first);
        root=Merge(y.first,y.second);
        root=Split(root,1).second;
    }
}
void Pushup(int u){
        a[u].Min=min(a[L(u)].Min,a[R(u)].Min);
        a[u].Min=min(a[u].Min,a[u].data);
        a[u].size=a[L(u)].size+a[R(u)].size+1;
}
void Rotate(int u){
        a[u].lazy^=1;
        swap(L(u),R(u));
}
void Pushdown(int u){
        a[u].lazy=0;
        if(L(u))Rotate(L(u));
        if(R(u))Rotate(R(u));
}
int Build(int left,int right){
        if(left>right)return 0;
        int mid=(left+right)>>1;
        int u=++num;
        a[u].lazy=0;
        a[u].data=A[mid];
        a[u].Min=Inf;
        L(u)=Build(left,mid-1);
        R(u)=Build(mid+1,right);
        Pushup(u);
        return u;
}
D Split(int u,int k){
        if(u==0)return D(0,0);
        if(a[u].lazy)Pushdown(u);
        D y;
        int num=a[L(u)].size;
        if(num>=k){
                y=Split(L(u),k);
                L(u)=y.second;
                Pushup(u);
                y.second=u;
        }else{
                y=Split(R(u),k-num-1);
                R(u)=y.first;
                Pushup(u);
                y.first=u;
        }
        return y;
}
int Merge(int A,int B){
        if(A==0)return B;
        if(B==0)return A;
        if(a[A].lazy)Pushdown(A);
        if(a[B].lazy)Pushdown(B);
        if(rand()%(a[A].size+a[B].size)<a[A].size){
                a[A].rch=Merge(a[A].rch,B);
                Pushup(A);
                return A;
        }
        else{
                a[B].lch=Merge(A,a[B].lch);
                Pushup(B);
                return B;
        }
}
int GetRank(int x){
        int u=root;
        int sum=0;
        while(1){
                if(a[u].data==x)return sum+a[L(u)].size+1;
                if(a[u].lazy)Pushdown(u);
                if(a[L(u)].Min==x)u=L(u);
                else sum+=a[L(u)].size+1,u=R(u);
        }
}

猜你喜欢

转载自www.cnblogs.com/holy-unicorn/p/9510138.html