文艺平衡树

文艺平衡树

题目

你需要写出一种数据结构去维护一个长度为 \(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\) 旋到根节点的右儿子,然后就是再交换一下两个儿子。

最终答案即是这颗 \(Splay\) 的中序遍历。

void reverse(int l, int r) {
	l = find(l - 1); r = find(r + 1);
	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);
		//这个l=find(l)是因为已经建立一个虚点原来的l-1变成了l
		//而r也是同理的
		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;
}
posted @ 2021-11-11 21:19  xxcxu  阅读(67)  评论(0编辑  收藏  举报