【splay】BZOJ 1152 && 3506:[cqoi2014]排序机械臂

BZOJ 1152 && 3506:[cqoi2014]排序机械臂


Description

这里写图片描述


Input

输入共两行,第一行为一个整数N,N表示物品的个数,第二行为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

1<=N<=100000


Solution

普通的序列splay…
每个数对应在splay中的编号不变
维护区间最小值所在的编号
每次rev标记一下即可
初始要离散化

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;

#define maxn 100233

struct splay{
    int ch[2],fa,size,v;
    bool rev;
}t[maxn*2];

int pos[maxn],mn[maxn],ans[maxn];

inline int in()
{
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
    return x;
}

int root;

struct sor{
    int pos,v;
}a[maxn];

bool cmp(const sor A,const sor B){return (A.v<B.v||(A.v==B.v&&A.pos<B.pos));}

bool cmp1(const sor A,const sor B){return A.pos<B.pos;}

void pushdown(int k)
{
    t[k].rev=0,t[t[k].ch[0]].rev^=1;t[t[k].ch[1]].rev^=1;
    swap(t[k].ch[0],t[k].ch[1]);
}

int find(int k,int x)
{
    if(t[k].rev)pushdown(k);
    if(t[t[k].ch[0]].size>=x)return find(t[k].ch[0],x);
    else if(x>t[t[k].ch[0]].size+1)return find(t[k].ch[1],x-t[t[k].ch[0]].size-1);
    else return k;
}

void update(int k)
{
    int l=t[k].ch[0],r=t[k].ch[1];
    t[k].size=t[l].size+t[r].size+1;
    mn[k]=t[k].v,pos[k]=k;
    if(mn[l]<mn[k]){mn[k]=mn[l];pos[k]=pos[l];}
    if(mn[r]<mn[k]){mn[k]=mn[r];pos[k]=pos[r];}
}


void rotate(int x,int &k,int d)
{
    int y,z;
    y=t[x].fa;z=t[y].fa;
    if(y==k)k=x;
    else {if(t[z].ch[0]==y)t[z].ch[0]=x;else t[z].ch[1]=x;}
    t[y].fa=x,t[x].fa=z,t[t[x].ch[d]].fa=y;
    t[y].ch[d^1]=t[x].ch[d];t[x].ch[d]=y;
    update(y),update(x);
}

int s[maxn],top=0;

void splay(int x,int &k)
{
    top=0;s[++top]=x;
    for(int i=x;t[i].fa;i=t[i].fa)
        s[++top]=t[i].fa;
    for(;top;top--)
        if(t[s[top]].rev)pushdown(s[top]);
    int y,z;
    while(x!=k)
    {
        y=t[x].fa;z=t[y].fa;
        if(y!=k)
        {
            if(t[z].ch[0]==y&&t[y].ch[0]==x)rotate(y,k,1);
            else if(t[z].ch[1]==y&&t[y].ch[1]==x)rotate(y,k,0);
            else if(t[z].ch[0]==y&&t[y].ch[1]==x)rotate(x,k,0);
            else if(t[z].ch[1]==y&&t[y].ch[0]==x)rotate(x,k,1);
        }
        if(t[t[x].fa].ch[0]==x)rotate(x,k,1);
        else rotate(x,k,0);
    }
}

void build(int l,int r,int f)
{
    if(r<l)return;
    if(l==r)
    {
        mn[l]=a[l].v;
        t[l].size=1;t[l].fa=f;
        t[l].v=a[l].v;
        pos[l]=l;
        t[f].ch[r>f]=r;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid-1,mid);build(mid+1,r,mid);
    t[mid].v=a[mid].v;
    update(mid);t[mid].fa=f;
    t[f].ch[mid>f]=mid;
}

int querymn(int L,int R)
{
    int ans1=find(root,L),ans2=find(root,R+2);
    splay(ans1,root),splay(ans2,t[root].ch[1]);
    return pos[t[ans2].ch[0]];
}

void rever(int L,int R)
{
    int ans1=find(root,L),ans2=find(root,R+2);
    splay(ans1,root),splay(ans2,t[root].ch[1]);
    t[t[ans2].ch[0]].rev^=1;
}

int main()
{
    freopen("1552.in","r",stdin);
    int n;
    n=in();
    a[1].v=a[n+2].v=99999999,mn[0]=99999999;
    for(int i=2;i<=n+1;i++)
    {
        a[i].v=in();
        a[i].pos=i-1;
    }
    sort(a+2,2+a+n,cmp);
    for(int i=2;i<=n+1;i++)a[i].v=i-1;
    sort(a+2,a+2+n,cmp1);
    build(1,n+2,0);
    root=(n+3)>>1;
    for(int i=1;i<=n;i++)
    {
        int x=querymn(i,n);
        splay(x,root);
        ans[i]=t[t[x].ch[0]].size;
        rever(i,ans[i]);
    }
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值