【模板】文艺平衡树
题目链接:ybt金牌导航4-3-2 / luogu P3391
题目大意
给一个数列,会有一些操作,把里面的一个区间翻转。
要你输出最后数列的样子。
思路
区间翻转,自然会想到这个是平衡树可以实现的操作。
然后怎么实现呢?其实就是把左边界的左边拎到根,右边界的右边拎到根的右儿子,然后从根右儿子的左儿子开始递归。
(这里左右边界的左右边不是直接读入的加减,而是求第几大的位置,因为你平衡树里面记的下标是数字,而不是位置)
每到一个点,就把左右儿子交换,然后继续递归两个儿子。
但是如果你每次都递归会超时,我们考虑用懒标记。
你就直接打标记,然后每次要下放的时候就翻转左右子树,然后给左右子树打标记,再清除自己的标记。
(别的操作不用管,也不要用,都不确定是否正确)
代码
#include<cstdio>
#include<iostream>
using namespace std;
struct Tree {
int l, r, fa, val, size;
bool lazy;
}tree[1000001];
int n, m, a[100003], x, y, root, tot;
int lef_root, rig_root;
bool son__p(int now) {
return tree[tree[now].fa].l == now;
}
void up(int now) {//更新大小
tree[now].size = tree[tree[now].l].size + tree[tree[now].r].size + 1;
}
void down(int now) {//lazy标记
if (tree[now].lazy) {
tree[tree[now].l].lazy ^= 1;
tree[tree[now].r].lazy ^= 1;
swap(tree[now].l, tree[now].r);
tree[now].lazy = 0;
}
}
void rotate(int now) {//旋转
int father = tree[now].fa;
int grand = tree[father].fa;
int son = son__p(now) ? tree[now].r : tree[now].l;
down(father);
down(now);
if (grand) son__p(father) ? tree[grand].l = now : tree[grand].r = now;
if (son__p(now)) tree[now].r = father, tree[father].l = son;
else tree[now].l = father, tree[father].r = son;
tree[now].fa = grand;
tree[father].fa = now;
if (son) tree[son].fa = father;
up(father);
up(now);
}
void splay(int x, int target) {//splay上提操作
while (tree[x].fa != target) {
if (tree[tree[x].fa].fa != target) {
son__p(x) == son__p(tree[x].fa) ? rotate(tree[x].fa) : rotate(x);
}
rotate(x);
}
if (!target) root = x;
}
int find(int x) {
int now = root;
while (now) {
if (x == tree[now].val) break;
if (x >= tree[now].val) now = tree[now].r;
else now = tree[now].l;
}
if (now != root) splay(now, 0);
return now;
}
int find_kth(int k) {//查询第k大的点的编号
int now = root;
while (now) {
down(now);
if (k <= tree[tree[now].l].size) now = tree[now].l;
else {
k -= tree[tree[now].l].size + 1;
if (!k) return now;
now = tree[now].r;
}
}
}
void insert(int x) {
int now = root, last = 0;
while (now) {
last = now;
tree[now].size++;
if (x < tree[now].val) now = tree[now].l;
else now = tree[now].r;
}
tot++;
tree[tot].fa = last;
tree[tot].val = x;
tree[tot].size = 1;
if (x < tree[last].val) tree[last].l = tot;
else tree[last].r = tot;
splay(tot, 0);
}
void join(int small, int big) {
tree[small].fa = tree[big].fa = 0;
int new_root = small;
while (tree[new_root].r)
new_root = tree[new_root].r;
splay(new_root, 0);
tree[new_root].r = big;
tree[big].fa = new_root;
}
void delete_(int x) {
splay(x, 0);
if (!tree[x].l && tree[x].r) tree[tree[x].r].fa = 0;
else if (tree[x].l && !tree[x].r) tree[tree[x].l].fa = 0;
else join(tree[x].l, tree[x].r);
tree[x].l = tree[x].r = 0;
}
int get_rank(int x) {
int now = find(x);
return tree[tree[now].l].size + 1;
}
void spilt(int x) {
int no_root = find(x);
lef_root = tree[no_root].l;
rig_root = tree[no_root].r;
tree[no_root].l = tree[no_root].r = 0;
}
int pre(int x) {
int now = root;
now = tree[now].l;
if (!now) return -1;
while (tree[now].r) {
now = tree[now].r;
}
return tree[now].val;
}
int nxt(int x) {
int now = root;
now = tree[now].r;
if (!now) return -1;
while (tree[now].l) {
now = tree[now].l;
}
return tree[now].val;
}
int build(int now, int l, int r) {//建造初始平衡树(根据原始序列)
if (l > r) return 0;
int mid = (l + r) >> 1;
tree[++tot].fa = now;
now = tot;
tree[now].lazy = 0;
tree[now].val = a[mid];
tree[now].l = build(now, l, mid - 1);
tree[now].r = build(now, mid + 1, r);
up(now);
return now;
}
void write(int now) {//输出最后的数组
down(now);
if (tree[now].l) write(tree[now].l);
if (tree[now].val != -1e9 && tree[now].val != 1e9)
printf("%d ", tree[now].val);
if (tree[now].r) write(tree[now].r);
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) a[i + 1] = i;
a[1] = -1e9;
a[n + 2] = 1e9;
root = build(0, 1, n + 2);
for (int i = 1; i <= m; i++) {
scanf("%d %d", &x, &y);
x = find_kth((x + 1) - 1);
y = find_kth((y + 1) + 1);
splay(x, 0);
splay(y, x);
tree[tree[tree[root].r].l].lazy ^= 1;
}
write(root);
return 0;
}