【luogu P3391】文艺平衡树(fhq Treap 做法)

文艺平衡树

题目链接:luogu P3391

题目大意

给一个数列,会有一些操作,把里面的一个区间翻转。
要你输出最后数列的样子。

思路

只是练练无旋 Treap 罢了。
就打个懒标记。
然后最后中序遍历过去就好了。

一定要记得 u p , d o w n up,down up,down

代码

#include<cstdio>
#include<cstdlib>
#include<iostream>

using namespace std;

int val[100001], ls[100001], rs[100001], turn[100001], yj[100001];
int size[100001];
int n, m, a[100001], x, y;
int sta[100001], tot, root;

int get_new(int num) {
	int now = ++tot;
	ls[now] = rs[now] = 0;
	turn[now] = 0;
	yj[now] = rand();
	val[now] = num;
	size[now] = 1;
	return now;
}

void up(int now) {
	size[now] = size[ls[now]] + size[rs[now]] + 1;
}

void turn_down(int now) {
	swap(ls[now], rs[now]); 
	turn[now] ^= 1;
} 

void down(int now) {
	if (turn[now]) {
		if (ls[now]) turn_down(ls[now]);
		if (rs[now]) turn_down(rs[now]); 
		turn[now] ^= 1;
	}
}

int build(int tot) {
	int now = get_new(a[1]);
	sta[++sta[0]] = now;
	
	for (int i = 2; i <= tot; i++) {
		now = get_new(a[i]);
		int lst = 0;
		
		while (sta[0] && yj[sta[sta[0]]] > yj[now]) {
			up(sta[sta[0]]);
			lst = sta[sta[0]];
			sta[sta[0]--] = 0;
		}
		
		ls[now] = lst;
		up(now);
		if (sta[0]) {
			rs[sta[sta[0]]] = now;
			up(sta[sta[0]]);
		}
		sta[++sta[0]] = now;
	}
	
	int lst = sta[sta[0]];
	while (sta[0]) {
		up(sta[sta[0]]);
		lst = sta[sta[0]];
		sta[sta[0]--] = 0;
	}
	return lst;
}

pair <int, int> split_rnk(int now, int rnk) {
	if (!now) return make_pair(0, 0);
	if (!rnk) return make_pair(0, now);
	
	pair <int, int> re;
	down(now);
	if (size[ls[now]] >= rnk) {
		re = split_rnk(ls[now], rnk);
		ls[now] = re.second;
		up(now);
		re.second = now;
	}
	else {
		re = split_rnk(rs[now], rnk - size[ls[now]] - 1);
		rs[now] = re.first;
		up(now);
		re.first = now;
	}
	
	return re;
}

int merge(int x, int y) {
	if (x) down(x);
	if (y) down(y);
	if (!x) return y;
	if (!y) return x;
	
	if (yj[x] < yj[y]) {
		rs[x] = merge(rs[x], y);
		up(x);
		return x;
	}
	else {
		ls[y] = merge(x, ls[y]);
		up(y);
		return y;
	}
}

void change_(int s, int t) {
	pair <int, int> x = split_rnk(root, s - 1);
	pair <int, int> y = split_rnk(x.second, t - s + 1);
	
	turn[y.first] ^= 1;
	swap(ls[y.first], rs[y.first]);
	
	root = merge(x.first, merge(y.first, y.second));
}

void write(int now) {
	down(now);
	
	if (ls[now]) write(ls[now]);
	printf("%d ", val[now]);
	if (rs[now]) write(rs[now]);
}

int main() {
	srand(19491001);
	
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		a[i] = i;
	
	root = build(n);
	
	while (m--) {
		scanf("%d %d", &x, &y);
		change_(x, y);
	}
	
	write(root);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值