Skip to content

洛谷 - P3391 【模板】文艺平衡树

检测到 KaTeX 加载失败,可能会导致文中的数学公式无法正常渲染。

题面

题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列。

其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 15\ 4\ 3\ 2\ 1,翻转区间是 [2,4][2, 4] 的话,结果是 5 2 3 4 15\ 2\ 3\ 4\ 1

输入格式

第一行两个正整数 n,mn, m,表示序列长度与操作个数。序列中第 ii 项初始为 ii。 接下来 mm 行,每行两个正整数 l,rl, r,表示翻转的区间。

输出格式

输出一行 nn 个正整数,表示原始序列经过 mm 次变换后的结果。

输入输出样例

样例输入 #1

5 3
1 3
1 3
1 4

样例输出 #1

4 3 2 1 5

数据范围与约定

对于 100%100\% 的数据,1n,m1000001 \le n, m \leq 1000001lrn1 \le l \le r \le n

思路

前置知识:无旋 Treap 学习笔记

当翻转 [l,r][l, r] 区间时,先分裂出 [1,r][1, r][r+1,size][r + 1, \mathit{size}] 两个区间,再从 [1,r][1, r] 中分裂出 [1,l1][1, l - 1][l,r][l, r] 两个区间。将 [l,r][l, r] 区间打标记后再合并即可。

最后按照中序遍历输出即为答案。

代码

#include <cstdlib>
#include <iostream>

using std::cin;
using std::cout;
#define endl '\n'

const int N = 1e5 + 5;

int n, m, l, r, root, cnt;

struct node {
    int l, r, s, v, k;
    bool d;

    node()
        : l(0), r(0), s(0), v(0), d(false), k(rand()) {}
    node(int _v)
        : l(0), r(0), s(1), v(_v), d(false), k(rand()) {}
} tr[N];

void pushup(int u) {
    tr[u].s = tr[tr[u].l].s + tr[tr[u].r].s + 1;
}

void pushdown(int u) {
    if (tr[u].d) {
        tr[u].d = false;
        tr[tr[u].l].d ^= 1;
        tr[tr[u].r].d ^= 1;
        std::swap(tr[u].l, tr[u].r);
    }
}

int build(int l, int r) {
    if (l > r) return 0;
    int mid = l + r >> 1;
    int p = ++cnt;
    tr[p] = node(mid - 1);
    tr[p].l = build(l, mid - 1);
    tr[p].r = build(mid + 1, r);
    pushup(p);
    return p;
}

std::pair<int, int> split(int p, int k) {
    if (!p) return std::make_pair(0, 0);
    pushdown(p);
    if (k <= tr[tr[p].l].s) {
        auto o = split(tr[p].l, k);
        tr[p].l = o.second;
        pushup(p);
        o.second = p;
        return o;
    }
    auto o = split(tr[p].r, k - tr[tr[p].l].s - 1);
    tr[p].r = o.first;
    pushup(p);
    o.first = p;
    return o;
}

int merge(int x, int y) {
    if (!x || !y) return x | y;
    pushdown(x);
    pushdown(y);
    if (tr[x].k > tr[y].k) {
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;
    }
    tr[y].l = merge(x, tr[y].l);
    pushup(y);
    return y;
}

void reserve(int l, int r) {
    auto x = split(root, r + 1);
    auto y = split(x.first, l);
    tr[y.second].d ^= 1;
    root = merge(merge(y.first, y.second), x.second);
}

void print(int p) {
    if (!p) return;
    pushdown(p);
    print(tr[p].l);
    if (1 <= tr[p].v && tr[p].v <= n) {
        cout << tr[p].v << ' ';
    }
    print(tr[p].r);
}

int main() {
    std::ios::sync_with_stdio(false);
    cin >> n >> m;
    root = build(1, n + 2);
    while (m--) {
        cin >> l >> r;
        reserve(l, r);
    }
    print(root);
    cout << endl;
    return 0;
}