HDU 3487(伸展树模板)

再也不想写第二次。

题意:给一个n一个q 表示一开始有n个数 接下来q个操作 CUT a b c表示把[a, b]剪切到c处,FILP a b 将[a, b]区间翻转。

伸展树搞。 看的题解:点击打开链接

代码挺好理解的感觉。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <cstring>
#include <cstdlib>
#define value ch[ch[root][1]][0]
using namespace std;
const int maxn = 300000 + 7;
const int INF = ~0U >> 1;
int n, q;
int size[maxn], k[maxn], pre[maxn], rev[maxn];
int ch[maxn][2];
int tot = 0, root;
int cnt = 0;

void newNode(int &r, int key, int fa) {
	r = ++tot;
	ch[r][0] = ch[r][1] = 0;
	pre[r] = fa;
	rev[r] = 0;
	k[r] = key;
}

void push_up(int r) {
	size[r] = size[ch[r][0]] + size[ch[r][1]] + 1;
}

void push_down(int r) {
	if(rev[r]) {
		swap(ch[r][0], ch[r][1]);
		rev[ch[r][0]] ^= 1;
		rev[ch[r][1]] ^= 1;
		rev[r] = 0;
	}
}

void Build(int &r, int left, int right, int fa) {
	if(left > right) return ;
	int mid = (left + right) / 2;
	newNode(r, mid, fa);
	Build(ch[r][0], left, mid - 1, r);
	Build(ch[r][1], mid + 1, right, r);
	push_up(r);
}

void init() {
	tot = root = cnt = 0;
	ch[root][0] = ch[root][1] = 0;
	pre[root] = size[root] = rev[root] = 0;
	newNode(root, -1, 0);
	newNode(ch[root][1], -1, root);
	size[root] = 2;
	Build(value, 1, n, ch[root][1]);
	push_up(ch[root][1]);
	push_up(root);
}

void Rotate(int x, int kind) {
	int y = pre[x];
	push_down(y);
	push_down(x);
	ch[y][!kind] = ch[x][kind];
	pre[ch[x][kind]] = y;
	if(pre[y]) ch[pre[y]][ch[pre[y]][1] == y] = x;
	pre[x] = pre[y];
	ch[x][kind] = y;
	pre[y] = x;
	push_up(y);
}

void splay(int r, int g) {
	push_down(r);
	while(pre[r] != g) {
		if(pre[pre[r]] == g)
			Rotate(r, ch[pre[r]][0] == r);
		else {
			int y = pre[r];
			int kind = (ch[pre[y]][0] == y);
			if(ch[y][kind] == r) {
				Rotate(r, !kind);
				Rotate(r, kind);
			} else {
				Rotate(y, kind);
				Rotate(r, kind);
			}
		}
	}
	push_up(r);
	if(g == 0) root = r;
}

int getKth(int r, int k) {
	push_down(r);
	int t = size[ch[r][0]];
	if(t == k - 1) return r;
	if(t >= k)
		return getKth(ch[r][0], k);
	else return getKth(ch[r][1], k - t - 1);
}

int getMin(int r) {
	push_down(r);
	while(ch[r][0]) {
		r = ch[r][0];
		push_down(r);
	}
	return r;
}

int getmax(int r) {
	push_down(r);
	while(ch[r][1]) {
		r = ch[r][1];
		push_down(r);
	}
	return r;
}

void reversal(int a, int b) {
	int x = getKth(root, a);
	int y = getKth(root,b + 2);
	splay(x, 0);
	splay(y, root);
	rev[value] ^= 1;
}

void cut(int a, int b, int c) {
	int x = getKth(root, a);
	int y = getKth(root, b + 2);
	splay(x, 0);
	splay(y, root);
	int temp = value;
	value = 0;
	push_up(ch[root][1]);
	push_up(root);
	int z = getKth(root, c + 1);
	splay(z, 0);
	int m = getMin(ch[root][1]);
	splay(m,root);
	value = temp;
	pre[value] = ch[root][1];
	push_up(ch[root][1]);
	push_up(root);
}

void print(int r) {
	if(!r) return ;
	push_down(r);
	print(ch[r][0]);
	if(cnt >= 1 && cnt <= n) {
		if(cnt > 1) printf(" ");
		printf("%d", k[r]);
	}
	++cnt;
	print(ch[r][1]);
}

int main() {
	while(scanf("%d%d", &n, &q) != EOF) {
		if(n == -1 && q == -1) break;
		init();
		while(q--) {
			char s[5] = {0};
			int a, b, c;
			scanf("%s", s);
			if(s[0] == 'C') {
				scanf("%d%d%d", &a, &b, &c);
				//cout << a << b << c << "==" << endl;
				cut(a, b, c);
			} else {
				scanf("%d%d", &a, &b);
				reversal(a, b);
			}
		}
		print(root);
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值