1. 程式人生 > >【BZOJ3506】[CQOI2014] 排序機械臂(Splay)

【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;
}