• 【BZOJ3506】[CQOI2014] 排序机械臂(Splay)


    点此看题面

    大致题意: 给你(n)个数。第一次找到最小值所在位置(P_1),翻转([1,P_1]),第二次找到剩余数中最小值所在位置(P_2),翻转([2,P_2]),以此类推。求(P_1,P_2,...,P_n)的值。

    关于洛谷上的四倍经验

    这题在洛谷上是一道四倍经验题(目前看来是两黑两紫):

    初始化

    这题应该是一道比较裸的(Splay)题。

    首先,我们将原数组排序一遍,记下每一次操作的位置

    有一个细节,题目要求相同值要先取位置靠前的(没注意到这点结果狂(WA)不止)。

    然后便是建树。

    注意,(Splay)建树的过程中我们一般会在序列左右各加一个多余节点,方便后面取出一段区间进行操作。

    操作

    每一次操作,我们把要操作的位置先(Splay)到根,然后就可以得出答案即为此时左子树的(Size),记其为(ans)

    注意是(Size)而不是(Size+1),要考虑到我们在序列左边加的那个多余节点已经使(Size)比实际存在的节点个数多(1)了。

    然后,按照题目要求,我们要翻转区间([i,ans])

    直接将(i)号节点和(ans+2)号节点分别旋到根节点和根节点的右儿子,然后翻转根节点的右儿子的左儿子即可。

    代码

    #include<bits/stdc++.h>
    #define Type template<typename I>
    #define N 100000
    #define swap(x,y) (x^=y^=x^=y)
    #define INF 1e9
    using namespace std;
    int n;
    struct Data
    {
        int pos,val;
        inline friend bool operator < (Data x,Data y) {return x.val^y.val?x.val<y.val:x.pos<y.pos;}
    }a[N+5];
    class Class_FIO
    {
        private:
            #define Fsize 100000
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
            #define pc(ch) (FoutSize^Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))
            #define Isi(x) (typeid(x).name()==typeid(1).name())
            #define Isc(x) (typeid(x).name()==typeid('a').name())
            int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
        public:
            Class_FIO() {A=B=Fin;}
            Type inline void read(I& x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
            Type inline void write(I x)
            {
                if(Isi(x)) {while(Stack[++Top]=x%10+48,x/=10);while(Top) pc(Stack[Top--]);}
                if(Isc(x)) pc(x);
            }
            template<typename I,typename... A> inline void read(I& x,A&... y) {read(x),read(y...);}
            template<typename I,typename... A> inline void write(I x,A... y) {write(x),write(y...);}
            inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
    }F;
    class Class_Splay//Splay
    {
        private:
            #define SIZE N
            #define PushUp(x) (node[x].Size=node[node[x].Son[0]].Size+node[node[x].Son[1]].Size+1)
            #define Rever(x) (swap(node[x].Son[0],node[x].Son[1]),node[x].Rev^=1)
            #define PushDown(x) (node[x].Rev&&(Rever(node[x].Son[0]),Rever(node[x].Son[1]),node[x].Rev=0))
            #define Which(x) (node[node[x].Father].Son[1]==x)
            #define Connect(x,y,d) (node[node[x].Father=y].Son[d]=x)
            #define Split(x,y) (Splay(get_pos(x),rt),Splay(get_pos((y)+2),node[rt].Son[1]),node[node[rt].Son[1]].Son[0])
            int rt;
            struct Tree
            {
                int Size,Rev,Father,Son[2];
            }node[SIZE+5];
            inline void Rotate(int x,int& k)
            {
                register int fa=node[x].Father,pa=node[fa].Father,d=Which(x);PushDown(fa),PushDown(x),
                (fa^k?node[pa].Son[Which(fa)]=x:k=x),node[x].Father=pa,Connect(node[x].Son[d^1],fa,d),Connect(fa,x,d^1),PushUp(fa),PushUp(x);
            }
            inline void Splay(int x,int& k) {register int fa;while(x^k) fa=node[x].Father,fa^k&&(Rotate(Which(x)^Which(fa)?x:fa,k),0),Rotate(x,k);}
            inline void Build(int l,int r,int& rt)
            {
                register int mid=l+r>>1;
                if(node[rt=mid].Size=1,!(l^r)) return;
                l<mid&&(Build(l,mid-1,node[rt].Son[0]),node[node[rt].Son[0]].Father=rt),
                r>mid&&(Build(mid+1,r,node[rt].Son[1]),node[node[rt].Son[1]].Father=rt),
                PushUp(rt);
            }
            inline int get_pos(int rk)
            {
                register int x=rt;
                while(x) 
                {
                    if(PushDown(x),node[node[x].Son[0]].Size>=rk) x=node[x].Son[0];
                    else if(!(rk-=node[node[x].Son[0]].Size+1)) return x;
                    else x=node[x].Son[1];
                }
            }
        public:
            inline void Init(int len) {Build(1,len+2,rt);}
            inline int GetAns(int x) 
            {
                register int k,ans;
                Splay(a[x].pos+1,rt),ans=node[node[rt].Son[0]].Size,k=Split(x,ans),Rever(k);//找到ans,然后翻转
                return ans;//返回答案
            }
            #undef SIZE
    }Splay;
    int main()
    {
        register int i,p;
        for(F.read(n),i=1;i<=n;++i) F.read(a[a[i].pos=i].val);//读入
        for(sort(a+1,a+n+1),Splay.Init(n),i=1;i<=n;++i) F.write(p=Splay.GetAns(i),' ');//初始化排序+依次操作
        return F.clear(),0;
    }
    
  • 相关阅读:
    制作USB启动盘
    Custom Content and Formatting 富文本框批量上传 quill
    “从特殊到一般”的思想
    每个元素应该有 相同的概率 被返回。
    前缀和
    graphql 案例
    电脑关机后怎么计算时间 CMOS电池 时钟芯片 晶体振荡器 晶振 时钟晶振 谐振电容
    前端质量|基于业务驱动的前端性能有效实践案例
    Pull or Push
    分区表出现错误 分区错误
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3506.html
Copyright © 2020-2023  润新知