C-Shuffle Cards平衡树

2022年01月18日,第五天

题目链接:C-Shuffle Cards_2021牛客国庆集训派对day3

学了几个平衡树回去翻了翻国庆积分赛的题,发现原来就是模板题,只能说自己学太少了QWQ。

下面提供三个思路,并且了解了平衡树实际上是用来维护树的中序遍历。

思路一:使用 F H Q   t r e a p FHQ\ treap FHQ treap 直接移动区间
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int N = 1e5 + 5;

struct node {
    int l, r;
    int val, key;
    int size;
}t[N];
mt19937 rnd (time(NULL));
int cnt, root;
inline int newnode (int val) {
    t[++ cnt].val = val;
    t[cnt].size = 1, t[cnt].key = rnd();
    t[cnt].l = t[cnt].r = 0;
    return cnt;
}

inline void pushup (int now) {
    t[now].size = t[t[now].l].size + t[t[now].r].size + 1;
}

void split (int now, int siz, int& x, int& y) {
    if (! now) x = y = 0;
    else {
        if (t[t[now].l].size < siz) {
            x = now;
            split (t[now].r, siz - t[t[now].l].size - 1, t[now].r, y);
        }else {
            y = now;
            split (t[now].l, siz, x, t[now].l);
        }
        pushup (now);
    }
}

int merge (int x, int y) {
    if (! x || ! y) return x | y;
    if (t[x].key < t[y].key) {
        t[x].r = merge (t[x].r, y);
        pushup (x);
        return x;
    }else {
        t[y].l = merge (x, t[y].l);
        pushup (y);
        return y;
    }
}

void inorder (int now) {
    if (! now) return ;
    inorder (t[now].l);
    cout << t[now].val << ' ';
    inorder (t[now].r);
}

void shuffle (int l, int r) {
    int x, y, z;
    split (root, l - 1, x, y);
    split (y, r - l + 1, y, z);
    root = merge (merge (y, x), z);
}

int main () {
    ios::sync_with_stdio (false), cin.tie (0), cout.tie(0);
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i ++)
        root = merge (root, newnode (i));
    while (m --) {
        int l, r; cin >> l >> r;
        shuffle (l, l + r - 1);
    }
    inorder(root);
    return 0;
}

思路二:使用 S p l a y Splay Splay 翻转三次区间
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;

struct node {
    int ch[2], fa, val, size;
    bool lazy;
}t[N];
int cnt, root;
inline void newnode (int& now, int val, int fa) {
    t[now = ++ cnt].val = val;
    t[now].fa = fa, t[now].size = 1;
}
inline void pushup (int now) {
    t[now].size = t[t[now].ch[0]].size + t[t[now].ch[1]].size + 1;
}
inline void pushdown (int now) {
    if (t[now].lazy) {
        swap (t[now].ch[0], t[now].ch[1]);
        t[t[now].ch[0]].lazy ^= 1;
        t[t[now].ch[1]].lazy ^= 1;
        t[now].lazy = 0;
    }
}
inline int ident (int x, int f) { return t[f].ch[1] == x; }
inline void connect (int x, int f, int s) {
    t[f].ch[s] = x, t[x].fa = f;
}
inline void rotate (int x) {
    int f = t[x].fa, ff = t[f].fa, k = ident (x, f);
    connect (t[x].ch[k ^ 1], f, k);
    connect (x, ff, ident (f, ff));
    connect (f, x, k ^ 1);
    pushup (f), pushup (x);
}

inline void splaying (int x, int top) {
    if (! top) root = x;
    while (t[x].fa != top) {
        int f = t[x].fa, ff = t[f].fa;
        if (ff != top) 
            ident (x, f) ^ ident (f, ff) ? rotate (x) : rotate (f);
        rotate (x);
    }
}

int getid (int siz) {
    int now = root;
    while (now) {
        pushdown (now);
        if (t[t[now].ch[0]].size + 1 == siz) {
            splaying (now, 0);
            break;
        }else if (t[t[now].ch[0]].size >= siz) 
            now = t[now].ch[0];
        else {
            siz -= t[t[now].ch[0]].size + 1;
            now = t[now].ch[1];
        }
    }
    return now;
}

void insert (int val) {
    int now = root, p = 0;
    while (now) p = now, now = t[now].ch[val > t[now].val];
    newnode (now, val, p);
    if (p) t[p].ch[val > t[p].val] = now;
    splaying (now, 0);
}

void reverse (int l, int r) {
    l = getid (l), r = getid (r + 2);
    splaying(l, 0), splaying (r, l);
    t[t[r].ch[0]].lazy ^= 1;
}

void output (int now) {
    if (! now) return ;
    pushdown (now);
    output (t[now].ch[0]);
    if (abs (t[now].val) < inf) 
        cout << t[now].val << ' ';
    output (t[now].ch[1]);
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n, m; cin >> n >> m;
    insert (inf), insert (-inf);
    for (int i = n; i >= 1; i --) insert (i);
    while (m --) {
        int l, r; cin >> l >> r;
        r += l - 1;
        reverse (1, l - 1);
        reverse (l, r);
        reverse (1, r);
    }
    output (root);
    return 0;
}
思路三:使用 S p l a y Splay Splay 直接移动区间
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;

struct node {
    int ch[2], val, size, fa;
}t[N];
int cnt, root;
inline void newnode (int& now, int fa, int val) {
    t[now = ++ cnt].val = val;
    t[now].fa = fa, t[now].size = 1;
}
inline void pushup (int x) {
    t[x].size = t[t[x].ch[0]].size + t[t[x].ch[1]].size + 1;
}
inline int ident (int x, int f) { return t[f].ch[1] == x; }
inline void connect (int x, int f, int s) {
    t[f].ch[s] = x, t[x].fa = f;
}
inline void rotate (int x) {
    int f = t[x].fa, ff = t[f].fa, k = ident (x, f);
    connect (t[x].ch[k ^ 1], f, k);
    connect (x, ff, ident (f, ff));
    connect (f, x, k ^ 1);
    pushup (f), pushup (x);
}
inline void splaying (int x, int top) {
    if (! top) root = x;
    while (t[x].fa != top) {
        int f = t[x].fa, ff = t[f].fa;
        if (ff != top) 
            ident (f, ff) ^ ident (x, f) ? rotate (x) : rotate (f);
        rotate (x);
    }
}
inline void insert (int val) {
    int u = root, p = 0;
    while (u) p = u, u = t[u].ch[val > t[u].val];
    newnode (u, p, val);
    if (p) t[p].ch[val > t[p].val] = u;
    splaying (u, 0);
}
void output (int u) {
    if (! u) return ;
    output (t[u].ch[0]);
    if (abs (t[u].val) < inf) 
          cout << t[u].val << ' ';
    output (t[u].ch[1]);
}
int ask (int siz) {
    int now = root;
    while (now) {
        if (t[t[now].ch[0]].size + 1 == siz) {
            splaying (now, 0);
            break;
        }else if (t[t[now].ch[0]].size >= siz) 
            now = t[now].ch[0];
        else {
            siz -= t[t[now].ch[0]].size + 1;
            now = t[now].ch[1];
        }
    }
    return now;
}
void shuffle (int l, int r) {
    if (l == 1) return ;
    l = ask (l - 1), r = ask (r + 1);
    splaying (l , 0), splaying (r, l);
    int k = t[r].ch[0];
    t[r].ch[0] = 0;
    pushup (r), pushup (l); 
    splaying (ask (1), 0);
    t[root].ch[0] = k, t[k].fa = root;
    pushup (root);
    splaying (l, 0);
}

int main() {
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i ++) insert (i);
    insert (inf);
    while (m --) {
        int l, r; cin >> l >> r;
        r += l - 1;
        shuffle (l, r);
    }
    output (root);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值