• LibreOJ2241


    Portal

    Description

    给出一个(n(nleq10^5))个数的序列({a_n}),对该序列进行(n)次操作。若在第(i)次操作前第(i)小的数在(p_i)位置,则翻转区间([i,p_i])。易知(n)次操作后序列会变为升序。求出每一次的(p_i)

    Solution

    splay。
    题里的(a_i)是会重复的...所以先离散化一波,相同的数按位置排名。然后根据初始位置建一棵splay,每次将(i)旋转到根求左子树大小即可,区间翻转用splay也很好实现。注意翻转需要加入在序列头尾加入两个哨兵节点。

    时间复杂度(O(nlogn))

    Code

    //「CQOI2014」排序机械臂
    #include <algorithm>
    #include <cstdio>
    using std::sort;
    inline char gc()
    {
        static char now[1<<16],*s,*t;
        if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
        return *s++;
    }
    inline int read()
    {
        int x=0; char ch=gc();
        while(ch<'0'||'9'<ch) ch=gc();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x;
    }
    inline void swap(int &x,int &y) {int t; t=x,x=y,y=t;}
    const int N=2e5+10;
    int n,a[N];
    int rt,fa[N],ch[N][2],siz[N]; bool rev[N];
    int wh(int p) {return p==ch[fa[p]][1];}
    void update(int p) {siz[p]=siz[ch[p][0]]+1+siz[ch[p][1]];}
    void rever(int p) {rev[p]^=1; swap(ch[p][0],ch[p][1]);}
    void pushdw(int p) {if(rev[p]) rever(ch[p][0]),rever(ch[p][1]),rev[p]=false;}
    void rotate(int p)
    {
        int q=fa[p],r=fa[q],w=wh(p);
        fa[p]=r; if(r) ch[r][wh(q)]=p;
        fa[ch[q][w]=ch[p][w^1]]=q;
        fa[ch[p][w^1]=q]=p;
        update(q),update(p);
    }
    void pushdwRt(int p) {if(fa[p]) pushdwRt(fa[p]); pushdw(p);}
    void splay(int p,int &k)
    {
        pushdwRt(p); int t=fa[k];
        for(int q=fa[p];q!=t;rotate(p),q=fa[p]) if(fa[q]!=t) rotate(wh(p)^wh(q)?p:q);
        update(k=p);
    }
    void bldTr(int &p,int L0,int R0)
    {
        if(L0>R0) return;
        int mid=L0+R0>>1; p=a[mid];
        bldTr(ch[p][0],L0,mid-1),bldTr(ch[p][1],mid+1,R0);
        fa[ch[p][0]]=fa[ch[p][1]]=p; update(p);
    }
    int rnk(int x)
    {
        int p=rt;
        while(true)
        {
            pushdw(p);
            if(x<=siz[ch[p][0]]) p=ch[p][0];
            else if(x==siz[ch[p][0]]+1) return p;
            else x-=siz[ch[p][0]]+1,p=ch[p][1];
        }
    }
    void split(int x,int y)
    {
        int p=rnk(x-1),q=rnk(y+1);
        splay(p,rt),splay(q,ch[rt][1]);
    }
    struct rec{int x,id;} tmp[N];
    bool cmpX(rec a,rec b) {return a.x==b.x?a.id<b.id:a.x<b.x;}
    void discrete()
    {
        for(int i=1;i<=n;i++) tmp[i].x=a[i],tmp[i].id=i;
        sort(tmp+1,tmp+n+1,cmpX);
        for(int i=1;i<=n;i++) a[tmp[i].id+1]=i+1;
        a[1]=1,a[n+2]=n+2;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        discrete(); bldTr(rt,1,n+2);
        for(int i=2;i<=n+1;i++)
        {
            splay(i,rt); int x=siz[ch[rt][0]]+1;
            printf("%d ",x-1);
            split(i,x),rever(ch[ch[rt][1]][0]);
        }
        return 0;
    }
    
  • 相关阅读:
    C# winform 获取鼠标点击位置
    C# 读取带有命名空间的xml
    ImageUtility辅助类
    C# 读取XML
    C# 根据生日获取年龄
    C# 将 WebService 封装成动态库
    C# 生成条形码
    C# Ftp Client 基本操作
    C# SQL帮助类
    C# 解压缩文件
  • 原文地址:https://www.cnblogs.com/VisJiao/p/LOJ2241.html
Copyright © 2020-2023  润新知