文藝平衡樹

甜桃奶芙發表於2021-11-11

文藝平衡樹

題目

你需要寫出一種資料結構去維護一個長度為 \(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 <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;
}

相關文章