【POJ3580】【块状链表】SuperMemo
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, {A1, A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:
- 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}
- 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}
- REVOLVE x y T: rotate sub-sequence {Ax ... Ay} T times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
- 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}
- DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
- 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 n (n ≤ 100000).
The following n lines describe the sequence.
Then follows M (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的更多相关文章
- 【BZOJ-1507】Editor 块状链表
1507: [NOI2003]Editor Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 3397 Solved: 1360[Submit][Stat ...
- ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)
题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...
- POJ 2887 Big String(块状链表)
题目大意 给一个字符串,长度不超过 106,有两种操作: 1. 在第 i 个字符的前面添加一个字符 ch 2. 查询第 k 个位置是什么字符 操作的总数不超过 2000 做法分析 好多不同的做法都可以 ...
- 【BZOJ 1507】【NOI 2003】&【Tyvj P2388】Editor 块状链表模板题
2016-06-18 当时关于块状链表的想法是错误的,之前维护的是一个动态的$\sqrt{n}$,所以常数巨大,今天才知道原因TwT,请不要参照这个程序为模板!!! 模板题水啊水~~~ 第一次写块状链 ...
- BZOJ 1507 Editor(块状链表)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1507 题意:一个文本编辑器,模拟以下操作: 思路:块状链表的主要操作: (1)find( ...
- bzoj 3809 Gty的二逼妹子序列(莫队算法,块状链表)
[题意] 回答若干个询问,(l,r,a,b):区间[l,r]内权值在[a,b]的数有多少[种]. [思路] 考虑使用块状链表实现莫队算法中的插入与删除. 因为权值处于1..n之间,所以我们可以建一个基 ...
- 【BZOJ1500】【块状链表】维修数列
Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述 ...
- 【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L
Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 .. ...
- 【BZOJ3295】【块状链表+树状数组】动态逆序对
Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...
- 【HDU4391】【块状链表】Paint The Wall
Problem Description As a amateur artist, Xenocide loves painting the wall. The wall can be considere ...
随机推荐
- 【转】Java ConcurrentModificationException 异常分析与解决方案--还不错
原文网址:http://www.2cto.com/kf/201403/286536.html 一.单线程 1. 异常情况举例 只要抛出出现异常,可以肯定的是代码一定有错误的地方.先来看看都有哪些情况会 ...
- Spark使用CombineTextInputFormat缓解小文件过多导致Task数目过多的问题
目前平台使用Kafka + Flume的方式进行实时数据接入,Kafka中的数据由业务方负责写入,这些数据一部分由Spark Streaming进行流式计算:另一部分数据则经由Flume存储至HDFS ...
- 原生javascript难点总结(1)---面向对象分析以及带来的思考
------*本文默认读者已有面向对象语言(OOP)的基础*------ 我们都知道在面向对象语言有三个基本特征 : 封装 ,继承 ,多态.而js初学者一般会觉得js同其他类C语言一样,有类似于Cl ...
- HDOJ(HDU) 4847 Wow! Such Doge!(doge字符统计)
Problem Description Chen, Adrian (November 7, 2013). "Doge Is An Ac- tually Good Internet Meme. ...
- (转)java多线程的一篇好文
云转型基石ThinkServer特性解析 2013-05-29 10:47 佚名 importnew 字号:T | T 本文只是一些针对初学者或者新手的问题,如果你已经具备良好的基础,那么你可以跳过本 ...
- 实现自己的脚本语言ngscript之零
正式开始介绍前先扯点没用的. 从小玩basic长大的小朋友大多有一个梦想,就是自己实现一个basic解释器. 不过这里我实现的不是basic,而是一个语法和功能类似javascript的东西. 暂且称 ...
- 2014 ACM-ICPC Asia Anshan Regional Contest(Online Version)
题目I - Osu! - HDU 5078 题目分析:最水的一道题吧,求两点间的距离和时间差值的最大比值 #include<stdio.h> #include<math.h> ...
- 从奥鹏一个答案提取页面 看jquery知识点
http://oldlearn.open.com.cn/OEMSExercise/HomeworkReview.aspx?HomeworkId=9c034488-0a3d-4b9d-a6cc-e42 ...
- UVa1608 UVaLive6258 Non-boring sequences
填坑系列(p.248) 比较神 从两端枚举 最坏复杂度就成O(nlogn)了 #include<cstdio> #include<cstdlib> #include<al ...
- poj 2462 Period of an Infinite Binary Expansion
欧拉定理.根据分数转换成2进制的过程,分子每次都乘2.对于循环节x,当2^x = 1(mod b)时肯定是循环节.显然当分母不能整除2的时候,即分母和2互质的话,就可以利用欧拉定理,使得2^(Eule ...