文艺平衡树
题目
你需要写出一种数据结构去维护一个长度为 \(n\) 的序列进行区间翻转。
总共会进行 \(m\) 次翻转, 你只需要输出这 \(m\) 次翻转后的最终序列。
Link to Luogu
数据范围
\(1 \leq n, m \leq 10 ^ 5\)
\(1 \leq l, r \leq n\)
序列初始时第 \(i\) 位为 \(i\)。
解题思路
假设大家已经学会了平衡树。
考虑使用平衡树,毕竟是文艺平衡树。
按照权值来做显然不太正确,于是就将下标存入平衡树。
能发现对于一次区间翻转 \([l, r]\) 可以转换为将 \(l - 1\) 节点旋转至根节点再将 \(r + 1\) 旋到根节点的右儿子,然后就是再交换一下两个儿子。
即
void reverse(int l, int r) {
l = find(l); r = find(r + 2);
Splay(l, 0); Splay(r, l);
}
为了考虑 \(1\) 和 \(n\) 的情况,不能使他们的左右儿子为空,那么就添加两个虚点。
这是我们会发现复杂度较高,不能通过此题(如果你过了,那么就是你常数的力量
那么就添加一个 \(lazytag\) 像线段树那样的。
每次不要急着翻转,打个标记就好了。
特别的就是注意下放的问题,真的很容易挂掉。
那么我们就得到了一份完整的代码(见下)。
实现代码
/*
@Author: Migou (Marachino)
@File: 333ms, 4.75MB, 2190+, C++11
*/
#include
using namespace std;
const int N = 1e5 + 5;
int n, m, root, tot;
namespace Splay {
struct splay {
int id, fa, siz, lazy;
int son[2];
void init(int x, int fa) {
id = x; this -> fa = fa;
siz = 1; lazy = 0; son[0] = son[1] = 0;
}
} tr[N << 1];
#define ls tr[rt].son[0]
#define rs tr[rt].son[1]
void pushup(int rt) {
tr[rt].siz = tr[ls].siz + tr[rs].siz + 1;
return void();
}
void pushdown(int rt) {
if (tr[rt].lazy) {
tr[ls].lazy ^= 1; tr[rs].lazy ^= 1;
tr[rt].lazy = 0; std::swap(ls, rs);
} return void();
}
void rotate(int x) {
int y = tr[x].fa, z = tr[y].fa;
int k = tr[y].son[1] == x;
tr[z].son[tr[z].son[1] == y] = x, tr[x].fa = z;
tr[y].son[k] = tr[x].son[k ^ 1], tr[tr[x].son[k ^ 1]].fa = y;
tr[x].son[k ^ 1] = y, tr[y].fa = x;
pushup(y), pushup(x); return void();
}
void Splay(int x, int goal) {
while (tr[x].fa != goal) {
int y = tr[x].fa, z = tr[y].fa;
if (z != goal)
rotate((y == tr[z].son[1]) ^ (x == tr[y].son[1])? x : y);
rotate(x);
} if (!goal) root = x;
return void();
}
void insert(int x) {
int rt = root, fa = 0;
while (rt) fa = rt, rt = tr[rt].son[x > tr[rt].id];
rt = ++ tot;
if (fa) tr[fa].son[x > tr[fa].id] = rt;
tr[rt].init(x, fa);
Splay(rt, 0); return void();
}
int find(int k) {
int rt = root;
while (114514) {
pushdown(rt);
if (tr[ls].siz >= k) rt = ls;
else if (tr[ls].siz + 1 == k) return rt;
else k -= tr[ls].siz + 1, rt = rs;
} return -1;
}
void reverse(int l, int r) {
l = find(l); r = find(r + 2);
Splay(l, 0); Splay(r, l);
tr[tr[tr[root].son[1]].son[0]].lazy ^= 1;
}
void print(int rt) {
pushdown(rt);
if (ls) print(ls);
if (1 < tr[rt].id && tr[rt].id < n + 2) std::cout << tr[rt].id - 1 << ' ';
if (rs) print(rs);
return void();
}
};
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
std::cin >> n >> m;
for (int i = 1; i <= n + 2; ++i) Splay::insert(i);
for (int i = 1, l, r; i <= m; ++i) {
std::cin >> l >> r;
Splay::reverse(l, r);
} Splay::print(root); std::cout << std::endl;
return (bool)"I Love CCF" & 0;
}