POJ 3580 SuperMemo (FHQ_Treap)

题意:让你维护一个序列,支持以下6种操作:

  ADD x y d: 第x个数到第y个数加d 。

  REVERSE x y : 将区间[x,y]中的数翻转 。

  REVOLVE x y t :将区间[x,y]循环移位t次,如1 2 3 4 5 旋转2次后就变成4 5 1 2 3 。

  INSERT x p :在第x个数后面插入p 。

  DELETE x :删除第x个数 。

  MIN x y : 查询区间[x,y]中的最小值 。
思路:此题有反转区间和循环移位的操作,所以我们很容易可以想到用 splay FHQ_treap 来解决这个问题。splay的操作比较麻烦,细节较多,而FHQ_Treap 简单暴力,只比splay慢一点点。

FHQ_Treap可以做splay能做的所有操作(插入,删除一段序列,区间操作,维护区间的值等),并且这些操作只和merge(合并)和split(分裂)这2个函数有关,不需要考虑各种细节,比较无脑。

代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <ctime>
#define INF ~0U>>2
using namespace std;
const int maxn=500010;
//struct FHQ_Treap {
	struct node {
		node* ch[2];
		int val, key, sz, mi, mark;
		bool flip;
		
		node() {
			val = INF;
			mark = sz = 0;
			mi = INF;
			flip = 0;
			key = rand();
		}
		
		inline void update() {
			sz = ch[0] -> sz + ch[1] ->sz + 1;
			mi = min(ch[0] -> mi, min(ch[1] -> mi, val));
		}
	};
	node *null = new node(), * root = null, *stack[maxn], *x, *last;
	typedef pair<node*, node*> pnn;
	int a[maxn], n;
	
	inline void maintain_flip(node* o) {
		if (o == null) return;
		o -> flip ^= 1;
	}
	
	inline void maintain_mark(node* o, int c) {
		if (o == null) return;
		o -> val += c;
		o -> mi  += c;
		o -> mark +=c;
	}
	
	inline void pushdown(node* o) {
		if (o == null) return;
		if (o -> flip) {
			o -> flip ^= 1;
			maintain_flip(o -> ch[0]);
			maintain_flip(o -> ch[1]);
			swap(o -> ch[0], o -> ch[1]);
		}
		if (o -> mark) {
			maintain_mark(o -> ch[0], o -> mark);
			maintain_mark(o -> ch[1], o -> mark);
			o -> mark = 0;
		}
	}
	
	inline node* newnode(int val) {
		node *o = new node();
		o ->ch[1] = o -> ch[0] = null;
		o -> key = rand();
		o -> val = o -> mi = val;
		o -> sz = 1;
		o -> flip = 0;
		o -> mark = 0;
		return o;
	}
	
	node* merge(node* a, node* b) {
		if (a == null) return b;
		if (b == null) return a;
		pushdown(a), pushdown(b);
		if (a -> key < b -> key) {
			a -> ch[1] = merge(a -> ch[1], b);
			a ->update();
			return a;
		} else {
			b -> ch[0] = merge(a, b -> ch[0]);
			b -> update();
			return b; 
		}
	}
	
	pnn split(node* o, int rnk) {
		if (o == null) return pnn(null, null);
		pnn y;
		pushdown(o);
		if (o -> ch[0] -> sz >= rnk) {
			y = split(o -> ch[0], rnk);
			o -> ch[0] = y.second;
			o -> update();
			y.second = o;
		}else {
			y = split(o -> ch[1], rnk - o -> ch[0] -> sz -1);
			o -> ch[1] = y.first;
			o -> update();
			y.first = o;
		}
		return y;
	}
	
	inline node* build() {
		int p = 0;
		for(int i = 1;i <= n; i++) {
			scanf("%d", &a[i]);
			x = newnode(a[i]);
			last = null;
			while(p && stack[p] -> key > x -> key) {
				stack[p] -> update();
				last = stack[p];
				stack[p--] = null;
			}
			if(p) stack[p] -> ch[1] = x;
			x -> ch[0] = last;
			stack[++p] = x;
		}
		while(p) stack[p--] -> update();
		return stack[1];
	}
	
	void del(node* o) {
		if(o == null) return;
		if(o -> ch[0] != null) del(o -> ch[0]);
		if(o -> ch[1] != null) del(o -> ch[1]);
		delete o;
	}
	
	inline void insert() {
		int pos, val;
		scanf("%d%d",&pos,&val);
		node* o = newnode(val);
		pnn x = split(root, pos);
		root = merge(merge(x.first, o), x.second);
	}
	
	inline void erase() {
		int pos;
		scanf("%d", &pos);
		pnn x = split(root, pos - 1);
		pnn y = split(x.second, 1);
		del(y.first);
		root = merge(x.first, y.second);
	}
	
	inline void reverse(void) {
		int L, R;
		scanf("%d%d",&L,&R);
		pnn x = split(root, L - 1);
		pnn y = split(x.second, R - L + 1);
		maintain_flip(y.first);
		root = merge(merge(x.first, y.first), y.second);
	}
	
	inline void make_add(void) {
		int L, R, c;
		scanf("%d%d%d", &L, &R, &c);
		pnn x = split(root, L - 1);
		pnn y = split(x.second, R - L + 1);
		maintain_mark(y.first, c);
		root = merge(merge(x.first, y.first),y.second);
	}
	
	inline int get_mi(void) {
		int L, R;
		scanf("%d%d",&L,&R);
		if(n == 0) return 0;
		pnn x = split(root, L - 1);
		pnn y = split(x.second, R - L + 1);
		pushdown(y.first);
		int ans = y.first -> mi;
		root = merge(merge(x.first, y.first),y.second);
		return ans;
	}
	
	inline void revove(void) {
		int L, R, t;
		scanf("%d%d%d", &L, &R, &t);
		int k = R - L + 1;
		t = (t % k + k) % k;
		if(t == 0) return;
		pnn x = split(root, L - 1);
		pnn y = split(x.second, k);
		pnn z = split(y.first, k - t);
		root = merge(merge(merge(x.first, z.second),z.first),y.second);
	}
//};
int main() {
	int m;
	scanf("%d", &n);
	root = build();
	char op[20];
	scanf("%d", &m);
	while(m--) {
		scanf("%s", op + 1);
		if (op[1] == 'I') {
			insert();
		} else if(op[1] == 'D') {
			erase();
		} else if(op[1] == 'A') {
			make_add();
		} else if(op[1] == 'M') {
			printf("%d\n", get_mi());
		} else if(op[1] == 'R') {
			if(op[4] == 'E')
				reverse();
			else
				revove();
		}
	}
} 

  代码实现参考了这篇博客:http://www.cnblogs.com/LadyLex/p/7182631.html

 

 

猜你喜欢

转载自www.cnblogs.com/pkgunboat/p/10238475.html
今日推荐