POJ3580 SuperMemo

遗世独立的理想乡

一道裸的splay题,对我来说比较有纪念意义,毕竟是第一次上手splay,最开始用的是红书的模板,倒是功能很齐全,但是略显麻烦,所以就换成了silver__bullet的模板,发现简单多了,估计过段时间就能裸敲了,而且,等我熟悉代码的机制以后应该可以往上加一些功能了吧,下一步应该就是treap,主席树,块链,树链剖分之类的东东了吧……

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = (int)1e6 + 10;
const int INF = 0x7fffffff;
int s[maxn];
struct splaytree{
	int cnt, root;
	int sz[maxn], ch[maxn][2], pre[maxn];
	int add[maxn], rev[maxn], minn[maxn], val[maxn];
	inline void newnode(int &t, int v){
		t = ++cnt;
		ch[t][0] = ch[t][1] = 0;
		add[t] = rev[t] = 0;
		sz[t] = 1;
		minn[t] = v;
		val[t] = v;
	}
	inline void PushUp(int x){
		sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
		minn[x] = min(min(minn[ch[x][0]], minn[ch[x][1]]), val[x]);
	}
	inline void PushDown(int x){
		if (rev[x]){
			if (ch[x][0]) rev[ch[x][0]] ^= 1;
			if (ch[x][1]) rev[ch[x][1]] ^= 1;
			swap(ch[x][0], ch[x][1]);
			rev[x] ^= 1;
		}
		if (add[x]){
			if (ch[x][0]){
				add[ch[x][0]] += add[x]; minn[ch[x][0]] += add[x]; val[ch[x][0]] += add[x];
			}
			if (ch[x][1]){
				add[ch[x][1]] += add[x]; minn[ch[x][1]] += add[x]; val[ch[x][1]] += add[x];
			}
			add[x] = 0;
		}
	}
	inline bool dir(int x){return ch[pre[x]][1] == x;}
	inline void link(int x, int y, int d){
		if (y) ch[y][d] = x;
		if (x) pre[x] = y;
	}
	inline void rotate(int x){
		int y = pre[x]; bool d = dir(x);
		PushDown(y); PushDown(x);
		link(x, pre[y], dir(y));
		link(ch[x][!d], y, d);
		link(y, x, !d);
		PushUp(y);
	}
	inline void splay(int x, int goal){
		PushDown(x);
		while (pre[x] != goal){
			if (pre[pre[x]] == goal) rotate(x);
			else {
				if (dir(x) == dir(pre[x])) rotate(pre[x]);
				else rotate(x);
				rotate(x);
			}
		}
		PushUp(x);
		if (goal == 0) root = x;
	}
	inline void select(int k, int goal){
		int x = root;
		PushDown(x);
		while(sz[ch[x][0]] != k){
			if (sz[ch[x][0]] > k) x = ch[x][0];
			else{
				k -= (sz[ch[x][0]] + 1); x = ch[x][1];
			}
			PushDown(x);
		}
		splay(x, goal);
	}
	inline int get(int ll, int rr){
		select(ll - 1, 0);
		select(rr + 1, root);
		return ch[root][1];
	}
	inline void build(int l, int r, int &t, int p){
		if (l > r) return;
		int m = (l + r) >> 1;
		newnode(t, s[m]);
		build(l, m - 1, ch[t][0], t);
		build(m + 1, r, ch[t][1], t);
		pre[t] = p;
		PushUp(t);
	}
	void init(int n){
		cnt = root = 0;
		sz[0] = ch[0][0] = ch[0][1] = pre[0] = 0;
		add[0] = rev[0] = 0;
		minn[0] = INF;
		val[0] = INF;
		newnode(root, INF);
		newnode(ch[root][1], INF);
		pre[cnt] = root;
		sz[root] = 2;
		build(1, n, ch[ch[root][1]][0], ch[root][1]);
		PushUp(ch[root][1]);
		PushUp(root);
	}
	inline void ADD(int ll, int rr, int d){
		int x = get(ll, rr);
		add[ch[x][0]] += d;
		minn[ch[x][0]] += d;
		val[ch[x][0]] += d;
		PushUp(x);
		PushUp(root);
	}
	inline void REVERSE(int ll, int rr){
		int x = get(ll, rr);
		rev[ch[x][0]] ^= 1;
	}
	inline void INSERT(int x, int val){
		select(x, 0);
		select(x + 1, root);
		newnode(ch[ch[root][1]][0], val);
		pre[ch[ch[root][1]][0]] = ch[root][1];
		PushUp(ch[root][1]);
		PushUp(root);
	}
	inline void RELOVE(int ll, int rr, int t){
		int len = (rr - ll + 1); t = (t % len + len) % len;
		if (t == 0) return;
		REVERSE(ll, rr - t);
		REVERSE(rr - t + 1, rr);
		REVERSE(ll, rr);
	}
	inline void DELETE(int P){
		int x = get(P, P);
		ch[x][0] = 0;
		PushUp(x);
		PushUp(root);
	}
	inline int MIN(int ll, int rr){
		int x = get(ll, rr);
		return minn[ch[x][0]];
	}
};
splaytree solver;
int main(){
/*	#ifndef ONLINE_JUDGE
	freopen("in", "rt", stdin);
	#endif*/
	int n, m, x, y, t;
	char op[10];
	while(scanf("%d", &n) == 1){
	for (int i = 1; i <= n; i++)
			scanf("%d", &s[i]);
		solver.init(n);
		scanf("%d", &m);
		while(m--){
			scanf("%s", op);
			if (op[0] == 'A'){
				scanf("%d%d%d", &x, &y, &t);
				solver.ADD(x, y, t);
			}else if (op[0] == 'R'){
				if (op[3] == 'E'){
					scanf("%d%d", &x, &y);
					solver.REVERSE(x, y);
				}else{
					scanf("%d%d%d", &x, &y, &t);
					solver.RELOVE(x, y, t);
				}
			}else if (op[0] == 'I'){
				scanf("%d%d", &x, &t);
				solver.INSERT(x, t);
			}else if (op[0] == 'D'){
				scanf("%d", &x);
				solver.DELETE(x);
			}else{
				scanf("%d%d", &x, &y);
				printf("%d\n", solver.MIN(x, y));
			}
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值