[CQOI2014]排序机械臂

[CQOI2014]排序机械臂

BZOJ
luogu
可以直接预处理出操作序列的下标,
相当于支持每次查询某个下标的排名以及区间翻转
对于询问可以额外记录fa,利用平衡树性质暴力跳fa求rank
区间翻转可以用fhq_treap,很短

#include<bits/stdc++.h>
using namespace std;
const int _=1e5+5;
int re(){
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
struct node{int v,id;}s[_];
int n,rt,top,fix[_],sz[_],fa[_],ls[_],rs[_],rev[_],st[_];
bool cmp(node a,node b){return a.v<b.v||(a.v==b.v&&a.id<b.id);}
void rever(int x){rev[x]^=1;swap(ls[x],rs[x]);}
void pd(int x){
    if(rev[x])rever(ls[x]),rever(rs[x]),rev[x]=0;
}
void pu(int x){sz[x]=sz[ls[x]]+sz[rs[x]]+1;fa[ls[x]]=x;fa[rs[x]]=x;}
void merge(int&x,int l,int r){
    if(!l||!r){x=l|r;return;}pd(l);pd(r);
    if(fix[l]>fix[r]){x=l;merge(rs[x],rs[l],r);}
    else{x=r;merge(ls[x],l,ls[r]);}pu(x);
}
void split(int x,int&l,int&r,int k){
    if(!x){l=r=0;return;}pd(x);
    if(k>=sz[ls[x]]+1){l=x;split(rs[l],rs[x],r,k-sz[ls[x]]-1);pu(l);}
    else{r=x;split(ls[r],l,ls[x],k);pu(r);}
}
int rk(int u){
    st[top=1]=u;
    for(int i=u;fa[i];i=fa[i])st[++top]=fa[i];
    while(top)pd(st[top--]);
    int res=sz[ls[u]];
    while(u){if(u==rs[fa[u]])res+=sz[ls[fa[u]]]+1;u=fa[u];}
    return res+1;
}
void reverse(int l,int r){
    int x,y,z;split(rt,x,y,r);split(x,x,z,l-1);
    rever(z);merge(x,x,z);merge(rt,x,y);
}
int main(){
    srand(time(NULL));
    n=re();
    for(int i=1;i<=n;i++){
        s[i]=(node){re(),i};sz[i]=1;
        fix[i]=rand();merge(rt,rt,i);
    }
    sort(s+1,s+n+1,cmp);
    for(int i=1;i<=n;i++){
        int k=rk(s[i].id);printf("%d ",k);reverse(i,k);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdzwyq/p/9919213.html