文藝平衡樹
題目
你需要寫出一種資料結構去維護一個長度為 \(n\) 的序列進行區間翻轉。
總共會進行 \(m\) 次翻轉, 你只需要輸出這 \(m\) 次翻轉後的最終序列。
資料範圍
\(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 <bits/stdc++.h>
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;
}