Description

Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:

  1. ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
  2. REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
  3. REVOLVE x y T: rotate sub-sequence {Ax ... AyT times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
  4. INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
  5. DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
  6. MIN x y: query the participant what is the minimum number in sub-sequence {Ax ... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2

To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls.

Input

The first line contains (≤ 100000).

The following n lines describe the sequence.

Then follows M (≤ 100000), the numbers of operations and queries.

The following M lines describe the operations and queries.

Output

For each "MIN" query, output the correct answer.

Sample Input

5
1
2
3
4
5
2
ADD 2 4 1
MIN 4 5

Sample Output

5

Source

【分析】
跟维修数列类似,不过多了几个操作,还需要合并。
还有点问题。
 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#define LOCAL
const int MAXN = + ;
const int INF = 0x7fffffff;
const int SIZE = ;
using namespace std;
struct Node{
int shu[SIZE + ];
int Min, addn, size;//块内最小值,需要加的n
Node *l, *r;
bool turn, add;//turn为翻转标记,add为增加标记 Node(){
Min = INF; addn = size = ;
l = r = NULL;
turn = add = ;
}
void update(){
if (turn){
for (int i = ; i <= (size>>); i++) swap(shu[i], shu[size - i + ]);
turn = ;
}
if (add){
add = ;
for (int i = ; i <= size; i++) shu[i] += addn;
Min += addn;
addn = ;
}
}
//统计最小值
void Count(){
update();
Min = INF;
for (int i = ; i <= size; i++) Min = min(shu[i], Min);
}
};
struct Block{
Node *head, *p;
int dir;//剩余的位置 Block(){head = new Node;}
//分裂p块
Node *split(Node *&t, int x){//从p的x位置开始分裂
t->update();
Node *p2 = new Node;
p2->r = t->r;
p2->l = t;
if (t->r != NULL) t->r->l = p2;
t->r = p2;
//[1,x]分到p中,[x+1,p->size]在p2中
memcpy(&p2->shu[], &t->shu[x + ], sizeof(int) * (t->size - x));
p2->size = t->size - x;//第一次写反了QAQ
t->size = x; t->Count();
p2->Count();
return p2;
}
Node *merge(Node *a, Node *b){
a->update();
b->update();
Node *t = new Node;
t->r = b->r;
t->l = a->l;
if (b->r != NULL) b->r->l = t;
if (a->l != NULL) a->l->r = t;
t->size = a->size + b->size;
memcpy(&t->shu[], &a->shu[], sizeof(int) * (a->size));
memcpy(&t->shu[a->size + ], &b->shu[], sizeof(int) * (b->size));
t->Count();
if (a->l == NULL)//说明是head
head = t;
delete a;
delete b;
return t;
}
void find(int x){
//路径压缩
int cnt = ;
p = head;
while (cnt + p->size < x){
cnt += p->size;
//if ((p->l != NULL) && (p->l->size + p->size <= (SIZE>>1)))
//p = merge(p->l, p);
if (p->size == && p != head){//删除空白块
p = p->l;
if (p->r != NULL) p->r = p->r->r;
else p->r = NULL;
if (p->r != NULL) p->r->l = p;
}
p = p->r;
}
dir = x - cnt;//注意这个值是直接在pos数组中的
}
//在pos位置插入num个数
void Insert(int pos, int num, int *data){
Node *p2;
find(pos);
if (pos == && head->size == ) goto w;
p->update();
//需要分裂
if (dir != p->size) {
p = split(p, dir);
p = p->l;
p = split(p, p->size);
}else p = split(p, dir); w:int i = ;
while (i <= num){
int tmp = min(SIZE - p->size, num - i + );
memcpy(&p->shu[p->size + ], &data[i], sizeof(int) * (tmp));
p->size += tmp;
i += tmp;
if (num >= i){
p->Count();
p = split(p, p->size);
}
}
p->Count();
}
void Delete(int pos, int num){//从pos位置开始删除num个数字
find(pos);
Node *p2;
while (num > ){
if ((dir == ) && (num >= p->size)){
num -= p->size;
if (p->l != NULL) p->l->r = p->r;
else head = p->r;
if (p->r != NULL) p->r->l = p->l;
p2 = p;
p = p->r;
delete p2;
}else{//不然就暴力删除
p->update();
int tmp = min(dir + num - , p->size);
num -= tmp - dir + ;
for (int i = ; i <= p->size - tmp; i++) p->shu[dir + i - ] = p->shu[tmp + i];
p->size -= tmp - dir + ;
p->Count();
p = p->r;
dir = ;
}
}
if (head == NULL) {head = new Node;}
}
//从pos位置开始给num个数字加上val
void add(int pos, int num, int val){
find(pos);
while (num > ){
if ((dir == ) && (num >= p->size)){
//p->update();
num -= p->size;
p->add = ;
p->addn += val;
p = p->r;
}else{
//打标记好像没必要update?
p->update();//会反转啊
int tmp = min(dir + num - , p->size);
num -= tmp - dir + ;
for (int i = ; i <= tmp - dir; i++) p->shu[i + dir] += val;
p->Count();
p = p->r;
dir = ;
}
}
}
int getMin(int pos, int num){
int Ans = INF;
find(pos);
while (num > ){
if ((dir == ) && (num >= p->size)){
p->Count();
num -= p->size;
Ans = min(Ans, p->Min);
p = p->r;
}else{//暴力判断
p->Count();
int tmp = min(dir + num - , p->size);
num -= tmp - dir + ;
for (int i = ; i <= tmp - dir; i++) Ans = min(p->shu[i + dir], Ans);
p = p->r;
dir = ;
}
}
return Ans;
}
//翻转
void Reverse(int pos, int num){
Node *ap, *bp, *cp, *dp;
Node *p2;
find(pos);
if (p->size >= dir + num - ){
p->update();
for (int i = ; i <= (num>>); i++)
swap(p->shu[dir + i - ], p->shu[num - i + dir]);
//p->Count();这样不会改变Min,不用改!
return;
}
if (dir > ){
num -= p->size - dir + ;
p2 = split(p, dir - );
ap = p2->l;
bp = p2;
p = p2->r; }else{//不然的话dir在一个整块上,
ap = p->l;
bp = p;
}
while (num > p->size){
num -= p->size;
p = p->r;
} //最后一块切割
if (num != p->size){
p2 = split(p, num);
cp = p2->l;
dp = p2;
}else{
cp = p;
dp = p->r;
}
p = bp;
while (){
swap(p->l, p->r);
p->turn = !p->turn;
if (p == cp) break;
p = p->l;
}
//大调换
if (dp != NULL) dp->l = bp;
bp->r = dp;
cp->l = ap;
if (ap != NULL) ap->r= cp;
else head = cp;
}
//旋转
//将[a,b]和[b+1, c]调换
void Revolve(int a, int b, int c){
if (b == c) return;
Node *z[], *y[];
Node *p2;
int L = c - a + ;//总长度
int L2 = b - a + ;//[a,b]的长度
find(a);
int num = L2;
//全部在一个块内
if (p->size >= dir + L - ){
int tmp[SIZE], cnt = ;
for (int i = dir + L2; i <= dir + L - ; i++) tmp[cnt++] = p->shu[i];
for (int i = dir; i <= dir + L2 - ; i++) tmp[cnt++] = p->shu[i];
for (int i = dir; i <= dir + L - ; i++) p->shu[i] = tmp[i - dir + ];
return;
}
//分割第一块
if (dir > ){
num -= p->size - dir + ;
p2 = split(p, dir - );
z[] = p2->l;
y[] = p2;
p = p2->r;
}else{
z[] = p->l;
y[] = p;
}
//中间的这一块
//num = L2;
while (num > p->size){
num -= p->size;
p = p->r;
}
int tmp = num;
num = L - L2;
if (tmp == p->size){
z[] = p;
y[] = p->r;
p = p->r;//这里还要走
}else if(tmp == ){
z[] = p->l;
y[] = p;
}else{
// num -= p->size - tmp;
p2 = split(p, tmp);
z[] = p2->l;
y[] = p2;
p = p2;
} while (num > p->size){
num -= p->size;
p = p->r;
} if (num == p->size){
z[] = p;
y[] = p->r;
}else if (num == ){
z[] = p->l;
y[] = p;
}else{
p2 = split(p, num);
z[] = p2->l;
y[] = p2;
}
//大调换!
if (z[] != NULL) z[]->r = y[];
else head = y[];y[]->l = z[];
if (y[] != NULL) y[]->l = z[];z[]->r = y[];
z[]->r = y[];
y[]->l = z[];
}
void print(){
Node *cur = head;
while (){
if (cur == NULL) break;
cur->update();
for (int i = ; i <= cur->size; i++) printf("%d ", cur->shu[i]);
cur = cur->r;
}
}
}A;
int n, data[MAXN];
char str[]; void debug();
void init(){
scanf("%d", &n);
for (int i = ; i <= n; i++) scanf("%d", &data[i]);
A.Insert(, n, data);
}
void work(){
//tot为数字总述
int m, tot = n;
scanf("%d", &m);
for (int i = ; i <= m; i++){
if (i == )
printf("");
scanf("%s", str);
if (str[] == 'A'){
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
if (r>= tot) A.add(l, r - l + , x);
}else if (str[] == 'I'){
int l, x;
scanf("%d%d", &l, &x);
data[] = x;
A.Insert(l, , data);
tot++;
}else if (str[] == 'M'){
int l, r;
scanf("%d%d", &l, &r);
if (r >= tot) printf("%d\n", A.getMin(l, r - l + ));
}else if (str[] == 'D'){
int l;
scanf("%d", &l);
tot--;
if (l >= tot) A.Delete(l, );
}else if (!strcmp(str, "REVERSE")){
int l, r;
scanf("%d%d", &l, &r);
if (l == r) continue;
if (r >= tot )A.Reverse(l, r - l + );
}else{
int l, r, t;
scanf("%d%d%d", &l, &r, &t);
//注意t可能为-
int len = r - l + ;
t = (t%len + len) % len;
if (t && r >= tot) A.Revolve(l, r - t, r);
}
}
}
void debug(){
data[] = ;
data[] = ;
data[] = ;
A.Insert(, , data);data[] = ; data[] = ;
A.Insert(, , data);data[] = ; data[] = ;
A.Insert(, , data);
//A.Reverse(2, 4);
//A.split(A.head, 1);
A.print();
printf("\n%d", A.getMin(, ));
} int main(){
#ifdef LOCAL
freopen("data.txt", "r", stdin);
freopen("std.txt", "w", stdout);
#endif
init();
work();
//debug();
return ;
}

【POJ3580】【块状链表】SuperMemo的更多相关文章

  1. 【BZOJ-1507】Editor 块状链表

    1507: [NOI2003]Editor Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 3397  Solved: 1360[Submit][Stat ...

  2. ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)

    题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...

  3. POJ 2887 Big String(块状链表)

    题目大意 给一个字符串,长度不超过 106,有两种操作: 1. 在第 i 个字符的前面添加一个字符 ch 2. 查询第 k 个位置是什么字符 操作的总数不超过 2000 做法分析 好多不同的做法都可以 ...

  4. 【BZOJ 1507】【NOI 2003】&【Tyvj P2388】Editor 块状链表模板题

    2016-06-18 当时关于块状链表的想法是错误的,之前维护的是一个动态的$\sqrt{n}$,所以常数巨大,今天才知道原因TwT,请不要参照这个程序为模板!!! 模板题水啊水~~~ 第一次写块状链 ...

  5. BZOJ 1507 Editor(块状链表)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1507 题意:一个文本编辑器,模拟以下操作: 思路:块状链表的主要操作: (1)find( ...

  6. bzoj 3809 Gty的二逼妹子序列(莫队算法,块状链表)

    [题意] 回答若干个询问,(l,r,a,b):区间[l,r]内权值在[a,b]的数有多少[种]. [思路] 考虑使用块状链表实现莫队算法中的插入与删除. 因为权值处于1..n之间,所以我们可以建一个基 ...

  7. 【BZOJ1500】【块状链表】维修数列

    Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述 ...

  8. 【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L

    Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 .. ...

  9. 【BZOJ3295】【块状链表+树状数组】动态逆序对

    Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...

  10. 【HDU4391】【块状链表】Paint The Wall

    Problem Description As a amateur artist, Xenocide loves painting the wall. The wall can be considere ...

随机推荐

  1. Linux Shell编程(25)——I/O 重定向

    默认情况下始终有3个"文件"处于打开状态, stdin (键盘), stdout (屏幕), and stderr (错误消息输出到屏幕上). 这3个文件和其他打开的文件都可以被重 ...

  2. (转载)浅谈javascript的分号

    (转载)http://www.blueidea.com/tech/web/2009/7261.asp javascript的分号代表语句的结束符,但由于javascript具有分号自动插入规则,所以它 ...

  3. 数据导出到Excel中

    自己修改后的一个数据导出到Excel的方法,粘出来与大家共享. 只需要将             System.Web.HttpContext.Current.Response.Charset =   ...

  4. C++Primer第5版学习笔记(四)

    C++Primer第5版学习笔记(四) 第六章的重难点内容         你可以点击这里回顾第四/五章的内容       第六章是和函数有关的知识,函数就是命名了的代码块,可以处理不同的情况,本章内 ...

  5. [转载]JVM性能调优--JVM参数配置

    http://www.cnblogs.com/chen77716/archive/2010/06/26/2130807.html

  6. Drawing Lines - SGU 135(简单递推)

    求N条直线最多能把一个平面分成几部分. 代码如下: ========================================================================== ...

  7. nyoj 67 三角形面积【三角形面积公式】

    三角形面积 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 给你三个点,表示一个三角形的三个顶点,现你的任务是求出该三角形的面积   输入 每行是一组测试数据,有6个 ...

  8. 网络子系统41_inet_peer平衡二叉树的删除

    //1.p存在左孩子,则使用p的左孩子的最右孩子替换p,然后重平衡树 //2.p不存在左孩子,则使用p的右孩子替换p,然后重平衡树 1.1 static void unlink_from_pool(s ...

  9. Page Cache buffer Cache

    https://www.thomas-krenn.com/en/wiki/Linux_Page_Cache_Basics References Jump up ↑ The Buffer Cache ( ...

  10. UVa12063 Zeros and Ones

    神坑 1竟然还要取模 在后面填数多好的 #include<cstdio> #include<cstring> #include<cstdlib> #include& ...