「Splay」區間翻轉


傳送門:>Here<

解法分析

  用splay來維護這個序列。

  一直沒有搞明白的是,這里的splay的節點究竟維護的是什么?是權值嗎?肯定不是,因為區間是會翻轉的,如果維護權值的話很快平衡樹就不再滿足性質。

  然而從頭到尾,唯一始終統一的就是位置——始終是1~n. 因此考慮用節點來維護位置。

  這樣在維護splay的時候,翻轉一段區間就相當於修改了這一段區間的位置,使原來小的現在大了,原來大的現在小了。放在樹上形象的看,就是原來作為父節點的左兒子的統統稱為了右兒子。反之亦然。因此只要找出連續的那一段區間,並且翻轉左右子樹即可。注意為了減少操作次數,可以打懶標記。

  如何找出連續的那一段目標區間?由於要翻轉的是區間$[l, r]$,我們可以找到位置(注意,這里的位置也就是平衡樹維護的權值的排名了,因此位置i也就是排名第i的)l-1和r+1的點,分別旋轉到根節點和根節點的右子樹上。這樣,根節點的右子節點的左子樹就是這段區間了。(想一想,為什么)。特殊的,當邊界到達1或n時會溢出,因此我們加入哨兵節點-1和n+1。這樣位置i就是排名i+1了。

  值得注意的是何時下傳懶標記——根據懶標記的優良傳統,不用就不翻轉。那唯一要用的時候就是詢問位置的時候了,因此只要find的時候下傳就可以了。另外翻轉兩次相當於不翻轉,所以用xor1會很方便。

  

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 100010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
    if(c == '-') w = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
    return x * w;
}
int n,m,L,R;
struct Splay{
    int ch[MAXN][2],size[MAXN],val[MAXN],fa[MAXN],tag[MAXN],num_node,root;
    inline bool Son(int f, int x){
        return ch[f][1]==x;
    }
    inline void Update(int x){
        size[x] = size[ch[x][1]] + size[ch[x][0]] + 1;
    }
    inline void Rotate(int x){
        int f = fa[x], gf = fa[f];
        bool p = Son(f, x), q = !p;
        ch[f][p] = ch[x][q];
        fa[ch[x][q]] = f;
        ch[x][q] = f;
        fa[f] = x;
        fa[x] = gf;
        if(gf != 0){
            ch[gf][Son(gf,f)] = x;
        }else{
            root = x;
        }
        Update(x), Update(f);
    }
    inline void splay(int x, int target){
        while(fa[x] != target){
            int f = fa[x], gf = fa[f];
            if(gf == target){
                Rotate(x);
                return;
            }
            if(Son(gf,f) == Son(f,x)){
                Rotate(f), Rotate(x);
            }
            else{
                Rotate(x), Rotate(x);
            }
        }
    }
    inline void Insert(int v){
        if(root == 0){
            ++num_node;
            root = num_node;
            size[num_node] = 1;
            val[num_node] = v;
            return;
        }
        for(int x = root; x != 0; x = ch[x][v >= val[x]]){
            bool b = v >= val[x];
            if(ch[x][b] == 0){
                ++num_node;
                ch[x][b] = num_node;
                size[num_node] = 1;
                val[num_node] = v;
                fa[ch[x][b]] = x;
                splay(ch[x][b], 0);
            }
        }
    }
    inline void Pushdown(int x){
        if(x == 0) return;
        if(!tag[x]) return;
        int tmp = ch[x][0];
        ch[x][0] = ch[x][1];
        ch[x][1] = tmp;
        tag[x] = 0;
        tag[ch[x][0]] ^= 1;
        tag[ch[x][1]] ^= 1;
    }
    inline int Find(int _k){
        int x = root;
        for(; x != 0;){
            Pushdown(x);
            if(size[ch[x][0]] + 1 == _k){
                return x;
            }
            if(size[ch[x][0]] >= _k){
                x = ch[x][0];
            }
            else{
                _k -= size[ch[x][0]] + 1;
                x = ch[x][1];
            }
        }
    }
    inline void Reverse(int L, int R){
        if(L >= R) return;
        splay(Find(L), 0);
        splay(Find(R), root);
        tag[ch[ch[root][1]][0]] ^= 1;
    }
    inline void DEBUG(){
        for(int i = 1; i <= n; ++i){
            printf("%d-->%d   lson:%d  rson:%d\n",i,val[i],ch[i][0],ch[i][1]);
        }
    }
}qxz;
int main(){
//    freopen(".in","r",stdin);
    n=r, m=r;
    qxz.Insert(-1);
    qxz.Insert(n+1);
    for(int i = 1; i <= n; ++i){
        qxz.Insert(i);
    }
//    qxz.DEBUG();
    for(int i = 1; i <= m; ++i){
        L=r, R=r;
        qxz.Reverse(L,R+2);
    }
    for(int i = 1; i <= n; ++i){
        printf("%d ", qxz.val[qxz.Find(i+1)]);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM