[平衡树-Splay]文艺平衡树_区间翻转

时间:2020-03-05 01:00:29   收藏:0   阅读:83

题意

给你一个1-n的排列,1,2,...n

求翻转k次之后的序列

例如:1,2,3,5,4 翻转2-4 -> 1,5,3,2,4

题解

代码

#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
const int inf = 0x3f3f3f;
#define Mid (l+r>>1)
int rt;//根节点
int tot;//节点个数
struct node {
    int fa;//父亲节点
    int ch[2];//子节点
    int val;//权值
    int tag;//标记
    int sz;//子树大小
}s[N];
int arr[N];

struct Splay {

    //在改变节点位置后,将节点x的size更新
    inline void maintain(int x) {
        s[x].sz = s[s[x].ch[0]].sz+s[s[x].ch[1]].sz + 1;
    }

    //判断该节点是左儿子还是右儿子
    inline bool get(int x) {return x == s[s[x].fa].ch[1];}


    inline void Rotate(int x) {
        int y = s[x].fa, z = s[y].fa, chk = get(x);

        //y与x的子节点相连
        s[y].ch[chk] = s[x].ch[chk ^ 1];
        s[s[x].ch[chk ^ 1]].fa = y;

        //x与y父子相连
        s[x].ch[chk ^ 1] = y;
        s[y].fa = x;

        // x与y的原来的父亲z相连
        s[x].fa = z;
        if(z) s[z].ch[y == s[z].ch[1]] = x;

        //只有x和y的sz变化了
        maintain(y);
        maintain(x);
    }
    //将当前节点转移到相应节点
    inline void splay(int x,int y) {
        for(int f = s[x].fa; f != y; Rotate(x),f = s[x].fa){
            if(s[f].fa != y) Rotate(get(x) == get(f) ? f : x);
        }
        if(y==0) rt = x;
    }

    //查询第k个数
    inline int getKth(int k) {
        int now = rt;
        while(true){
            pushDown(now);
            if(s[now].ch[0] && k <= s[s[now].ch[0]].sz){
                now = s[now].ch[0];
            }else{
                k -= s[s[now].ch[0]].sz + 1;
                if(k <= 0){
                    return now;
                }
                now=s[now].ch[1];
            }
        }
    }
    //初始化
    int build(int f,int l,int r){
        if(l>r) return 0;
        int x = ++tot;
        s[x].fa = f;
        s[x].val = arr[Mid];
        s[x].tag = 0;
        s[x].ch[0] = build(x,l,Mid - 1);//与线段树不同,该节点包括了mid这个值
        s[x].ch[1] = build(x,Mid + 1,r);
        maintain(x);
        return x;
    }
    //下传标记
    void pushDown(int x) {
        if(x&&s[x].tag) {
            s[s[x].ch[0]].tag ^= 1;
            s[s[x].ch[1]].tag ^= 1;
            swap(s[x].ch[0],s[x].ch[1]);
            s[x].tag = 0;
        }
    }
    //翻转(l,r),先锁定区间
    void Reverse(int l,int r) {
        int x = getKth(l),y = getKth(r+2);
        splay(x,0);
        splay(y,x);
        s[s[y].ch[0]].tag ^= 1;
    }
    //中序遍历输出
    void solve(int now){
        pushDown(now);
        if(s[now].ch[0]) solve(s[now].ch[0]);
        if(s[now].val != -inf && s[now].val != inf) printf("%d ",s[now].val);
        if(s[now].ch[1]) solve(s[now].ch[1]);
    }

    void debug(int n){
        int x = getKth(1),y=getKth(5);
        splay(x,0);
        splay(y,x);
    }
}st;
int main(){
    int n,k;
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;++i) arr[i+1] = i;
    arr[1] = -inf;
    arr[n+2] = inf;
    rt = st.build(0,1,n+2);
    int l=0,r=0;
    for(int i=1;i<=k;++i){
        scanf("%d %d",&l,&r);
        st.Reverse(l,r);
    }
    st.solve(rt);
    return 0;
}

原文:https://www.cnblogs.com/smallocean/p/12417066.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!