Shuffle Cards(splay)

题目链接:https://vjudge.net/problem/Gym-247729C

题意:长度为 n 的一叠牌,从上往下编号为 1 - n,然后 m 次操作,每次把从 a 开始往下数 b 张牌(包括 a)放到整叠牌的最上面,m 次操作之后,输出从上往下每张牌的编号。

Input
第一行输入 n 和 m,≤ n, m ≤ 1e5,然后 m 行,每行两个数 a , b,表示从 a 开始往下数 b 张牌(包括 a)放到整叠牌的最上面。
Output
输出从上往下每张牌的编号。

Sample Input

5 3

2 3

1 4

2 4

Sample Output

3 4 1 5 2

思路:假设我们要把 a 这个区间放到最前面,那么我们可以先翻转 a 区间,再翻转 b 区间,最后翻转 c 区间就可以实现了,然后就可以用 splay 去做这道题。

splay学习:https://www.cnblogs.com/lsl127/p/12884891.html

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;

typedef long long ll;

const int N = 100010;

struct node
{
    int data;
    int lazy;
    int cnt, siz;
    int fa, son[2];
} tree[N];

int n, m;
int root, totnode;
int a[N];
int ans[N], top;

int get_side(int num)
{
    int fa = tree[num].fa;
    return tree[fa].son[1] == num;
}

void update(int num)
{
    if(num == 0) return ;
    int l = tree[num].son[0];
    int r = tree[num].son[1];
    tree[num].siz = tree[num].cnt;
    if(l) tree[num].siz += tree[l].siz;
    if(r) tree[num].siz += tree[r].siz;
}

void Rotate(int c)
{
    int b = tree[c].fa;
    int a = tree[b].fa;
    int w = get_side(c);
    int w2 = get_side(b);
    int d = tree[c].son[w ^ 1];
    tree[b].son[w] = d;
    tree[d].fa = b;
    tree[c].son[w ^ 1] = b;
    tree[c].fa = a;
    tree[b].fa = c;
    if(a)
    {
        tree[a].son[w2] = c;
    }
    update(b);
    update(c);
}

void splay(int c, int tar)
{
    while(tree[c].fa != tar)
    {
        int b = tree[c].fa;
        int a = tree[b].fa;
        if(a != tar)
        {
            if(get_side(c) == get_side(b)) Rotate(b);
            else Rotate(c);
        }
        Rotate(c);
    }
    if(tar == 0) root = c;
}

void pushdown(int num)
{
    tree[num].lazy = 0;
    int l = tree[num].son[0];
    int r = tree[num].son[1];
    tree[l].lazy ^= 1;
    tree[r].lazy ^= 1;
    int tmp = l;
    tree[num].son[0] = r;
    tree[num].son[1] = tmp;
}

int Find(int x)
{
    int pos = root;
    while(1)
    {
        if(tree[pos].lazy) pushdown(pos);
        int l = tree[pos].son[0];
        int r = tree[pos].son[1];
        int lsiz = tree[l].siz;
        if(l && lsiz >= x) pos = l;
        else
        {
            int tmp = tree[pos].cnt;
            if(l) tmp += tree[l].siz;
            if(x <= tmp) return pos;
            x -= (tmp);
            pos = r;
        }
    }
}

void get_ans(int now)
{
    if(tree[now].lazy) pushdown(now);
    int l = tree[now].son[0];
    int r = tree[now].son[1];
    if(l) get_ans(l);
    if(tree[now].data != -inf && tree[now].data != inf) ans[top++] = tree[now].data;
    if(r) get_ans(r);
}

void Reverse(int l, int r)
{
    splay(Find(l - 1), 0);
    splay(Find(r + 1), root);
    int now = tree[tree[root].son[1]].son[0];
    tree[now].lazy ^= 1;
}

void print()
{
//    cout << top << endl;
    for(int i = 0; i < top; i++)
    {
        if(i == top - 1) printf("%d\n", ans[i]);
        else printf("%d ", ans[i]);
    }
    return ;
}

void fun(int x, int y)
{
    int l = x + 1;
    int r = x + y;
    Reverse(l, r);
    Reverse(2, l - 1);
    Reverse(2, r);
}

int build(int l, int r, int fa)
{
    if(l > r) return 0;
    int now = ++totnode;
    int mid = (l + r) / 2;
    tree[now].data = a[mid];
    tree[now].fa = fa;
    tree[now].lazy = 0;
    tree[now].cnt = 1;
    tree[now].son[0] = build(l, mid - 1, now);
    tree[now].son[1] = build(mid + 1, r, now);
    update(now);
    return now;
}

int main()
{
    int x, y;
    scanf("%d %d", &n, &m);
    n += 2;
    a[1] = -inf;
    a[n] = inf;
    for(int i = 2; i < n; i++) a[i] = i - 1;
    root = build(1, n, 0);
    for(int i = 1; i <= m; i++)
    {
        scanf("%d %d", &x, &y);
        fun(x, y);
    }
    top = 0;
    get_ans(root);
    print();
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/lsl127/p/12911216.html