【模板】 Splay树

Splay

Messenger(板子题)

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;

char str[N];

namespace Splay{
	struct Node{
		int son[2];
		int fa, val, size, cnt;
		int rev;
	}t[N];

	int root, tot;

	void push_up(int x){
		t[x].size = t[t[x].son[0]].size + t[t[x].son[1]].size + 1;
	}
	
	void push_down(int x){
		if(t[x].rev){
			swap(t[x].son[0], t[x].son[1]);
			t[ t[x].son[0] ].rev ^= 1;
			t[ t[x].son[1] ].rev ^= 1;
			t[x].rev = 0;
		}
	}

	int getson(int x){return t[t[x].fa].son[1] == x;}//是父亲哪个儿子
	void rotate(int x){
		int y = t[x].fa, z = t[y].fa, tt = getson(x);
		if(z)
			t[z].son[getson(y)] = x;
		else 
			root = x;
		t[x].fa = z;
		int tmp = t[x].son[!tt];
		t[y].son[tt] = tmp;
		if(tmp)
			t[tmp].fa = y;
		t[x].son[!tt] = y;
		t[y].fa = x;
		push_up(y), push_up(x);
	}

	void splay(int x, int goal){//让序号为x的节点做goal的儿子
		while(t[x].fa != goal){
			int y = t[x].fa, z = t[y].fa;
			if(z != goal)
				(getson(x) == getson(y)) ? rotate(y) : rotate(x);
			rotate(x);
		}
		if(goal == 0) root = x; 
	}

	int kth(int x){//找第k大的数
		int u = root;
		while(1){
			push_down(u);
			if(t[u].son[0] && x <= t[t[u].son[0]].size){
				u = t[u].son[0];
			}
			else {
				int tmp = (t[u].son[0] ? t[t[u].son[0]].size : 0) + 1;
				if(x == tmp)
					return u;
				x -= tmp;
				u = t[u].son[1];
			}
		}
	}
	void insert(int x){
		int u = root, fa = 0;
		while(u && t[u].val != x){
			fa = u;
			u = t[u].son[x > t[u].val];
		}
		//if(u) t[u].cnt++;
		u = ++tot;
		t[u].cnt = t[u].size = 0;
		t[u].son[0] = t[u].son[1] = 0;
		t[u].fa = fa;
		t[u].val = x;
		if(fa) t[fa].son[x > t[fa].val] = u;

		splay(u, 0);
	}

	void splay_rev(int l, int r){
		int ed =  kth(r + 1), st = kth(l - 1);
		splay(st, 0);
		splay(ed, st);
		t[ t[ed].son[0] ].rev ^= 1;
	}

	void print(int p){
		if(!p) return;
		push_down(p);
		print(t[p].son[0]);
		if(t[p].val != -inf && t[p].val != inf)
			printf("%c",str[t[p].val]);
		print(t[p].son[1]);
	}
}
using namespace Splay;
int main(){
	scanf("%[^\n]", str + 1); getchar();
	int len = strlen(str + 1);

	insert(-inf);
	for(int i = 1; i <= len; i++) insert(i);
	insert(inf);

	int m;
	scanf("%d", &m);
	while(m--){
		int p;
		scanf("%d", &p);
		splay_rev(1 + 1, 1 + p);
		splay_rev(1 + p + 1, 1 + len);
	}
	print(root);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值