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