1. 程式人生 > >Hdu 3487 play the chain 題解(fhq_treap)

Hdu 3487 play the chain 題解(fhq_treap)

3487: Play with Chain

Time Limit: 10 Sec Memory Limit: 256 MB

Description

瑤瑤很喜歡玩項鍊,她有一根項鍊上面有很多寶石,寶石從1到n編號。
首先,項鍊上的寶石的編號組成一個序列:1,2,3,...,n。
她喜歡兩種操作:
1.CUT a b c:他會先將a至b號寶石切下來,然後接到c號寶石後面,組成一個新的項鍊。
舉個例子,如果n=8,那麼這個項鍊上的寶石編號依次為:1 2 3 4 5 6 7 8;'CUT 3 5 4',首先我們把3到5號寶石切下
項鍊變成了:1 2 6 7 8;然後接到4號寶石後面,此時的4號寶石為7,所以此時的項鍊變成了:1 2 6 7 3 4 5 8.
2.FLIP a b:像第一個操作一樣我們先將a至b號寶石切下來,然後將其旋轉180°,變成與原來相反的鏈,在插入到項鍊的相 同位置中。
舉個例子,取操作1中的鏈:1 2 3 4 5 6 7 8,執行FLIP 2 6操作,則項鍊將變成:1 6 5 4 3 2 7 8.
他想知道經過m個操作之後項鍊會變成怎樣。

Input

對於每一個數據,第一行會有兩個整數:\(n,m(1\leq n,m\leq 300000)\) \(n\)代表寶石的個數,\(m\)代表操作的個數。
接下來有\(m\)行 有兩個操作:
CUT A B C //代表CUT操作,\(1\leq A\leq B\leq N, 0\leq C\leq N-(B-A+1)\).
FLIP A B //代表FLIP操作,\(1\leq A\leq B\leq N\).
輸出的結尾將會有兩個負數,他們不能當做操作.

Output

對於每一個數據,你需要輸出\(n\)個整數,任兩個數字間用一個空格分開,代表最終得到的項鍊的從1到\(n\)的寶石的序列號。

Sample Input

8 2
CUT 3 5 4
FLIP 2 6
-1 -1

Sample Output

1 4 3 7 6 2 5 8

HINT


題意:

\(n\)個元素的序列,\(m\)個操作,支援剪下區間和翻轉區間兩種操作
原序列為1 2 3 4 5 6 7 8
cut操作,先將3~5號元素剪下下來
序列變為1 2 6 7 8
此時四號元素為7,再將剪下下來的元素放在7後面
序列變為1 2 6 7 3 4 5 8
flip操作,翻轉2~6號元素
得1 4 3 7 6 2 5 8


題解

分析題意,題目讓我們維護一個序列,支援兩種操作,可以考慮楊fhq_treap來寫
考慮到cut操作,其實就是先將a~b分離出來再插入到c號元素之後即可,直接split和merge即可完成此操作
至於flip操作,分離出a~b區間,再打Lazy標記即可
詳見程式碼

#include<bits/stdc++.h>
#define F(i,j,n) for(register int i=j;i<=n;i++)
#define INF 0x3f3f3f3f
#define ll long long
#define mem(i,j) memset(i,j,sizeof(i))
using namespace std;
int n,m,ansnum=0;
inline int read(){
    int datta=0;char chchc=getchar();bool okoko=0;
    while(chchc<'0'||chchc>'9'){if(chchc=='-')okoko=1;chchc=getchar();}
    while(chchc>='0'&&chchc<='9'){datta=datta*10+chchc-'0';chchc=getchar();}
    return okoko?-datta:datta;
}
class Fhq_Treap{
    private:
    public:
    int tot,son[1200010][2],key[1200010],val[1200010],sz[1200010];
    inline void updata(int u){
        sz[u]=sz[son[u][0]]+sz[son[u][1]]+1;
    }
    inline void build(int l,int r,int lst){
        if(r<l)
            return ;
        if(l==r){
            son[lst][lst<l]=l;
            key[l]=rand();
            val[l]=l;
            sz[l]=1;
            return ;
        }
        int mid=(l+r)>>1;
        son[lst][lst<mid]=mid;
        key[mid]=rand();
        val[mid]=mid;
        build(l,mid-1,mid);
        build(mid+1,r,mid);
        updata(mid);
    }
    inline void make_rev_tag(int u){
        rev[u]^=1;
        swap(son[u][0],son[u][1]);
    }
    inline void pushdown(int u){
        if(rev[u]){
            if(son[u][0])
                make_rev_tag(son[u][0]);
            if(son[u][1])
                make_rev_tag(son[u][1]);
            rev[u]=0;
        }
    }
    inline pair<int,int>split(int u,int k){
        if(!k)
            return make_pair(0,u);
        if(k==sz[u])
            return make_pair(u,0);
        pushdown(u);
        if(k<=sz[son[u][0]]){
            pair<int,int>res=split(son[u][0],k);
            son[u][0]=res.second;
            updata(u);
            return make_pair(res.first,u);
        }else{
            pair<int,int>res=split(son[u][1],k-sz[son[u][0]]-1);
            son[u][1]=res.first;
            updata(u);
            return make_pair(u,res.second);
        }
    }
    inline int merge(int x,int y){
        if(!x||!y)
            return x+y;
        pushdown(x);
        pushdown(y);
        if(key[x]<key[y]){
            son[x][1]=merge(son[x][1],y);
            updata(x);
            return x;
        }else{
            son[y][0]=merge(x,son[y][0]);
            updata(y);
            return y;
        }
    }
    int rt;
    bool rev[1200010];
    inline void prepare(){
        tot=n;
        rt=(1+n)>>1;
        build(1,n,0);
    }
    inline void rever(int l,int r){
        pair<int,int>spl1=split(rt,r);
        pair<int,int>spl2=split(spl1.first,l-1);//分離a~b區間
        make_rev_tag(spl2.second);//打Lazy標記
        rt=merge(merge(spl2.first,spl2.second),spl1.second);
    }
    inline void print_ans(int u){
        if(!u)
            return ;
        pushdown(u);
        print_ans(son[u][0]);
        if(ansnum==n-1)
            printf("%d",val[u]);
        else
            printf("%d ",val[u]);//避免PE
        ansnum++;
        print_ans(son[u][1]);
    }
}F;
int main(){
    n=read();m=read();
    while(n!=-1&&m!=-1){
        mem(F.son,0);mem(F.key,0);mem(F.val,0);mem(F.sz,0);mem(F.rev,0);
        F.rt=F.tot=ansnum=0;
        F.prepare();//建初始樹
        F(i,1,m){
            char ch=getchar();
            while(ch!='C'&&ch!='F')
                ch=getchar();
            int a=read(),b=read(),c;
            if(ch=='C'){
                c=read();
                pair<int,int>spl1=F.split(F.rt,b);
                pair<int,int>spl2=F.split(spl1.first,a-1);
                F.rt=F.merge(spl2.first,spl1.second);//上面三行分離出a~b區間
                pair<int,int>spl3=F.split(F.rt,c);//分離c區間
                F.rt=F.merge(F.merge(spl3.first,spl2.second),spl3.second);//重新組合
            }else{
                F.rever(a,b);//翻轉操作
            }
        }
        F.print_ans(F.rt);//按前序遍歷輸出答案
        printf("\n");
        n=read();m=read();
    }
    return 0;
}