题意:让你维护一个序列,支持以下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

POJ 3580 SuperMemo (FHQ_Treap)的更多相关文章

  1. poj 3580 SuperMemo

    题目连接 http://poj.org/problem?id=3580 SuperMemo Description Your friend, Jackson is invited to a TV sh ...

  2. POJ 3580 - SuperMemo - [伸展树splay]

    题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in ...

  3. 平衡树(Splay):Splaytree POJ 3580 SuperMemo

    SuperMemo         Description Your friend, Jackson is invited to a TV show called SuperMemo in which ...

  4. POJ 3580 SuperMemo (splay tree)

    SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6841   Accepted: 2268 Case Ti ...

  5. Splay树(多操作)——POJ 3580 SuperMemo

    相应POJ题目:点击打开链接 SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 11309   Accept ...

  6. POJ 3580 SuperMemo 伸展树

    题意: 维护一个序列,支持如下几种操作: ADD x y D:将区间\([x,y]\)的数加上\(D\) REVERSE x y:翻转区间\([x,y]\) REVOLVE x y T:将区间\([x ...

  7. POJ 3580:SuperMemo(Splay)

    http://poj.org/problem?id=3580 题意:有6种操作,其中有两种之前没做过,就是Revolve操作和Min操作.Revolve一开始想着一个一个删一个一个插,觉得太暴力了,后 ...

  8. 【POJ 3580】SuperMemo Splay

    题意 给定$n$个数,$m$个询问,每次在$[L,R]$区间加上一个数,或者反转一个区间$[L,R]$,或者循环右移区间$[L,R]$共$T$次,或者在第$x$个数后插入一个数$p$,或者删除第$x$ ...

  9. 【POJ 3580】 SuperMemo

    [题目链接] 点击打开链接 [算法] 本题也是Splay区间操作的模板题,不过要比BZOJ 3223要稍微复杂一些,做完此题后,我终于对Splay有了更深入的理解,有“拨开云雾见青天”的感觉 本题还是 ...

随机推荐

  1. Postman工具——Pre-Request Script、Tests

    这篇是介绍 Postman 的最后一篇,也就是最后两个用法:Pre-Request Script 和 Tests ,它支持以嵌入脚本的方式动态准备测试数据,并根据业务需求设计测试用例. 一.Pre-R ...

  2. 算法练习1---桶排序java版

    今天复习了桶排序. 例如现在有满分为10分的试卷,学生得分分别为2,8,5,3,5,7,现在要给这些分数按照从大到小输出,使用桶排序的思想:有11个桶,每个桶有一个编号,编号从0-10,每出现一个分数 ...

  3. mac上完整卸载删除:android studio方案

    如果你是mac  ,你删除as ,删不干净也正常,你会发现安装的时候,前面的东西也在.配置文件在,会导致你以前的错误不想要的东西都在. 废话不多说,复制粘贴!!~~~~~~~~ 第一步: 复制粘贴!! ...

  4. ASP.NET MVC中加入Web Forms

    目的 有时候在一个ASP.NET MVC项目发布之后,又需要添加动态页面,同时又不想重新在源代码中添加view,那么这时候就要用上Web Forms了. 步骤 1.在项目根目录添加一个文件夹,在文件夹 ...

  5. 【Window Service】关于Window Service的两三事

    引言  Window Service通常用于寄宿WCF服务或者定时作业.下面记录一下它的用法. 创建 创建Window Service项目后,可以看到Program和Service1类.Program ...

  6. 条款44:将与参数无关的代码剥离template

    使用template时,不小心的时候可能就会带来代码膨胀的问题: template<typename T, std::size_t n> class SquareMatrix{ publi ...

  7. cmd命令之查看进程到杀掉进程

    1. cmd命令查看当前进程 netstat -ano | findstr “port”

  8. 15_游戏编程模式EventQueue

    #### 两个例子 .GUI event loop ``` while (running) { // 从事件队列里获取一个事件 Event event = getNextEvent(); // Han ...

  9. mac下cocos+android在.bash_profile文件里的配置

    既包含了已经消失了的老板本"cocos"软件相关的配置,也包含当时最新的cocos2d-x-3.11引擎包的相关配置 支持把cocos引擎相关代码预编译出库文件存放到prebuil ...

  10. 团队开发中Git冲突解决

    正常来说我们团队协作开发过程中,冲突是常有的事,下面介绍下本人在开发中的解决办法. 冲突的主要原因就是由于我们开发人员在分支的同一位置写入了不一样的代码,然后合并到主干上导致我们冲突. 方法: 当冲突 ...