1 2 3 4

文艺平衡树 - FHQ treap

https://www.luogu.com.cn/problem/P3391

这平衡树太厉害了。

思想就是分裂成1--x-1    x---y   y---n三段,然后给x----y这段树打上lazy标记

在合并和分裂时候都要先下传标记才行

具体看代码就好,留个模板记录一下

 

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 1e6 + 111;
struct Node {
	int val, key;
	int l, r, siz;
}tree[maxn];
int cnt = 0;
int lazy[maxn];

void add(int x) {
	++cnt;
	tree[cnt].val = x;
	tree[cnt].l = tree[cnt].r = 0;
	tree[cnt].siz = 1;
	tree[cnt].key = rand();
}

void push(int node) {
	swap(tree[node].l, tree[node].r);

	lazy[tree[node].l] ^= 1;
	lazy[tree[node].r] ^= 1;

	lazy[node] = 0;
}

void update(int node) {
	tree[node].siz = tree[tree[node].l].siz + tree[tree[node].r].siz + 1;
}
void split(int node, int x, int& l, int& r) {
	if (node == 0) {
		l = r = 0;
		return ;
	}
	if (lazy[node]) push(node);//标记下传

	if (tree[tree[node].l].siz + 1 <= x) {
		l = node;
		split(tree[node].r, x - tree[tree[node].l].siz - 1, tree[node].r, r);
		//当前树的右子树也有部分要切成l集合
	}
	else {
		r = node;
		split(tree[node].l, x, l, tree[node].l);
	}
	update(node);
}

int merge(int l, int r) {
	if (!l || !r) return l + r;

	if (tree[l].key < tree[r].key) {
		if (lazy[l]) push(l);

		tree[l].r = merge(tree[l].r, r);
		update(l);
		return l;
	}
	else {
		if (lazy[r]) push(r);

		tree[r].l = merge(l, tree[r].l);
		update(r);
		return r;
	}

}
int root, l, r, p;

int dfs(int x) {
	if (x == 0) return 0;
	if (lazy[x]) push(x);

	dfs(tree[x].l);
	printf("%d ", tree[x].val);

	dfs(tree[x].r);
	return 0;
}



int main() {
	int n, m;
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		add(i);
		root = merge(root, cnt);
	}


	for (int i = 0; i < m; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		split(root, y, l, r);
		split(l, x - 1, l, p);
		//p树部分
		lazy[p] ^= 1;

		root = merge(merge(l, p), r);
	}
	dfs(root);
	return 0;
}

  

posted @ 2020-11-07 16:32  Lesning  阅读(85)  评论(0编辑  收藏  举报