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

时间:2023-01-08 14:02:35

Description

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

Input

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

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

HINT

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

Source

【分析】
发现大家都是用splay做的,觉得用块状链表好像也可以做,结果真的可以....,捣鼓了一个下午,终于弄出来了.....
其实想好了还是很简单的(那你还做了一个下午,太弱了)。
用论文上的方法进行删除和添加数值,虽然效率有点低下,但是对付这道题还是够了。
因为没有牵涉到合并,因此不会涉及到标记的合并等等。
其实牵涉到了也没关系.....update一下就可以暴力合并,复杂度不会上升。
 #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> const int MAXN = ;
const int INF = ;
const int SIZE = ;
using namespace std;
struct Node{
int shu[SIZE+];
int size, sum, samen;
int lmax, rmax, mmax;
Node *l, *r;
bool turn, same; Node(){//构造函数
size = sum = samen = same = ;
lmax = rmax = mmax = -INF;
l = r = NULL;
turn = ;
}
//对于两个较小的数列合并也要update
void update(){
if (same){//是否改为同样的
for (int i = ; i <= size; i++) shu[i] = samen;
turn = ;same = ;
return;
}
if (!turn){//反转序列
for (int i = ; i <= (size>>);i++) swap(shu[i], shu[size - i + ]);
swap(lmax, rmax);
turn = ;
}
}
void Count(){
update();
int t = ;
sum = ;
rmax = lmax = mmax = -INF;
//序列中间的一段和
for (int i = ; i <= size; i++){
sum += shu[i];
t = max(t + shu[i], shu[i]);
mmax = max(t, mmax);
}
t = ;
for (int i = ; i <= size; i++) {t += shu[i]; lmax = max(lmax, t);}t = ;
for (int i = size; i >= ; i--) {t += shu[i]; rmax = max(rmax, t);}
}
};
//块状链表
struct Block{
Node *head, *p;
int dir; Block(){head = new Node;}
void find(int x){//移动到x所在的块,顺便压缩路径
int tmp = ;
p = head;
while (p->size + tmp < x){
tmp += p->size;
if (p->size == ){
p = p->l;
p->r = p->r->r;
if (p->r != NULL) p->r->l = p;
}
p = p->r;
}
dir = x - tmp;
}
//将a分成a和b两个块
Node *NEW(Node *&a){
Node *b = new Node;
b->r = a->r;
b->l = a;
if (a->r != NULL) a->r->l = b;
a->r = b;
return b;
}
void Insert(int pos,int size,int *data){ //插入操作
Node *p2;
find(pos);
p->update();
//如果指向中间,就分裂,注意这一段在开头也同样可以操作!
if (dir != p->size){
//这种操作与普通的块状链表有点不一样,但是更加便于理解
p2 = NEW(p);
memcpy(&p2->shu[], &p->shu[dir + ], sizeof(int) * (p->size - dir)); p2->size = p->size - dir;
p->size = dir; p2->Count();
p->Count();
}
int i = ;//插入数列
while (i <= size){
int tmp = min( - p->size, size - i + );
memcpy(&p->shu[p->size + ], &data[i], sizeof(int)*tmp);
i += tmp;
p->size += tmp;
if (size >= i){//创建新的列表再加入
p->Count();
p2 = NEW(p);
p = p2;
}
}
p->Count();
}
void Delete(int pos,int num){
Node *p2;
find(pos);
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();
//tmp记录能删除的最远位置
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 = ;
}
}
}
//反转操作
void Reverse(int pos, int num){
Node *ap,*bp,*cp,*dp;
Node *p2;
bool first=true;
int tmp;
find(pos); if (p->size >= dir + num - ){//直接暴力
p->update();
for (int i = ; i <= (num >> ); i++) swap(p->shu[dir + num - i], p->shu[dir + i - ]);
p->Count();
return;
}
if (dir > ){//拆第一块
p->update();
num -= p->size - dir + ;
p2 = NEW(p);
memcpy(&p2->shu[], &p->shu[dir], sizeof(int)*(p->size-dir+));
p2->size = p->size - dir + ;
p->size = dir - ; ap = p2;
cp = p;
p2->Count();
p->Count();
p = p2->r;
}else{
ap = p;
cp = ap->l;
}
while (num > p->size){
num -= p->size;
p = p->r;
}
//最后一块也要拆
if (num != p->size){
p->update();
p2 = NEW(p);
memcpy(&p2->shu[],&p->shu[num+],sizeof(int)*(p->size-num));
p2->size = p->size - num;
p->size = num; bp = p;
dp = p2;
p2->Count();
p->Count();
}else{
//简单的反转一下
bp = p;
dp = p->r;
}
//从开头开始大反转
p = ap;
while (){
swap(p->l, p->r);
p->turn = !p->turn;
swap(p->lmax, p->rmax);
if (p == bp) break;
p = p->l;//注意因为已经换了所以是向左走
}
//将整个块倒转
if (cp != NULL) cp->r = bp;
else head = bp;
ap->r = dp;
bp->l = cp;
if (dp != NULL) {dp->l = ap;}
}
//使一段序列变成相同的值
void MakeSame(int pos,int num,int val){
find(pos);
while (num > ){
if ((dir == ) && (num >= p->size)){
//整块操作
p->same = ;
p->samen = val;
p->sum = p->size * val;
p->mmax = max(val, p->sum);//注意因为val可能是负数,所以要这样写
p->rmax = p->lmax = p->mmax;
num -= p->size;
p = p->r;
}else{
p->update();//暴力操作
int tmp = min(dir + num - , p->size);
for (int i = dir; i <= tmp; i++) p->shu[i] = val;
p->Count();
num -= tmp - dir + ;
p = p->r;
dir = ;
}
}
}
//区间和
int GetSum(int pos,int x){
int tmp = ;
find(pos);
while (x > ){
if ((dir == ) && (x >= p->size)){
tmp += p->sum;
x -= p->size;
p = p->r;
}else{ //暴力
p->Count();
int t = min(dir + x - , p->size);
for (int i = dir; i <= t; i++) tmp += p->shu[i];
x -= t - dir + ;
p = p->r;
dir = ;
}
}
return tmp;
}
//区间最大值
int MaxSum(){
int Ans = -INF, last = -INF;
p = head;
while (p != NULL){
if (p->size != ){
int tmp;
tmp = max(last + p->sum, max(p->rmax, p->sum));
Ans = max(Ans, max(last + p->lmax, max(tmp, p->mmax)));
last = tmp;
}
p = p->r;
}
return Ans;
}
}A; int m, pos;
int n,tmp, data[MAXN];
char str[]; void init(){
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) scanf("%d", &data[i]);
tmp = ;
A.Insert(tmp, n, data);
}
void work(){
for (int i = ; i <= m; i++){
scanf("%s", str);
if (str[] != 'X') scanf("%d%d", &pos, &n);
if (str[] == 'S'){
for (int i = ; i <= n; i++) scanf("%d", &data[i]);
A.Insert(pos, n, data);
}else if (str[] == 'L') A.Delete(pos, n);
else if (str[] == 'K') {
int tmp;
scanf("%d", &tmp);
A.MakeSame(pos, n, tmp);
}else if (str[] == 'T') printf("%d\n", A.GetSum(pos, n));
else if (str[] == 'V') A.Reverse(pos,n);
else if (str[] == 'X') printf("%d\n", A.MaxSum());
}
} int main(){
#ifdef LOCAL
freopen("data.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
init();
work();
return ;
}

【BZOJ1500】【块状链表】维修数列的更多相关文章

  1. 【BZOJ1500】&lbrack;NOI2005&rsqb;维修数列 Splay

    [BZOJ1500][NOI2005]维修数列 Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行 ...

  2. 【BZOJ1500】&lbrack;NOI2005&rsqb;维修数列

    Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一 ...

  3. BZOJ1500:&lbrack;NOI2005&rsqb;维修数列——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1500 https://www.luogu.org/problemnew/show/P2042#su ...

  4. BZOJ1500:&lbrack;NOI2005&rsqb;维修数列

    浅谈\(splay\):https://www.cnblogs.com/AKMer/p/9979592.html 浅谈\(fhq\)_\(treap\):https://www.cnblogs.com ...

  5. &lbrack;BZOJ1500&rsqb;&lbrack;NOI2005&rsqb;维修数列---解题报告

    Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...

  6. 【BZOJ1500】【NOI2005】维修数列(Splay)

    [BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...

  7. &lbrack;BZOJ1500&rsqb;&lbrack;NOI2005&rsqb;维修数列 解题报告 Splay

    Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...

  8. &lbrack;bzoj1500&rsqb;&lbrack;NOI2005&rsqb;维修数列&lowbar;非旋转Treap

    维修数列 bzoj-1500 NOI-2005 题目大意:给定n个数,m个操作,支持:在指定位置插入一段数:删除一个数:区间修改:区间翻转.查询:区间和:全局最大子序列. 注释:$1\le n_{ma ...

  9. 【BZOJ-1500】维修数列 Splay

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 11047  Solved: 3460[Submit][Statu ...

随机推荐

  1. STM32 复合设备编写

    目的 完成一个CDC + MSC的复合USB设备 可以方便在CDC,MSC,复合设备三者间切换 可移植性强 预备知识 cube中USB只有两个入口. main函数中的MX_USB_DEVICE_Ini ...

  2. css3 自定义动画(1)

    <style> /*@-webkit-keyframes 动画名称 {} 用时:-webkit-animation:时间 动画名称; */ /* @-webkit-keyframes mo ...

  3. Win &plus; D 和 Win &plus; M的区别

    在Windows系统上,Win + D是显示桌面,Win + M是最小化所有窗口,咋一看,这两个快捷键貌似没有区别,但是在某些方面还是有细微的区别. 威力 从威力上来说,Win + D更牛逼一,因为显 ...

  4. mybatis的动态sql

    案例一: insert语句,然后获取这条语句的id值. <insert id="insertBook" parameterType="modle.Book&quot ...

  5. java&period;util&period;Map&period;Entry接口

    java.util.Map.Entry接口主要就是在遍历map的时候用到,给你个例子:package test;import java.util.*;import java.util.Map.Entr ...

  6. &lbrack;LightOJ 1287&rsqb; Where to Run

    Where to Run Last night you robbed a bank but couldn't escape and when you just got outside today, t ...

  7. python实现http接口自动化测试(完善版)

    今天给大家分享一个简单的Python脚本,使用python进行http接口的自动化测试,脚本很简单,逻辑是:读取excel写好的测试用例,然后根据excel中的用例内容进行调用,判断预期结果中的返回值 ...

  8. http&colon;&sol;&sol;www&period;bootcss&period;com&sol;p&sol;font-awesome&sol;

    集成 将Font Awesome 集成到 Bootstrap 非常容易,还可以被单独使用. 最简单的 Bootstrap + Font Awesome 集成方式 使用这种方式将 Font Awesom ...

  9. windows安装oracle client 18c 和plsql工具

    安装须知: (1)安装平台选择.linux/windows (2)软件位数选择.32/64,如果你的plsql工具是32位,那么你就安装32位客户端,如果是64位,你就安装64位客户端. 安装过程: ...

  10. 设计模式13---桥接模式(Bridge Pattern)

    桥接模式将抽象与具体实现分离,使得抽象与具体实现可以各自改变互不影响.桥接模式属于设计模式中的结构模式. 桥梁模式涉及的角色 抽象(Abstraction)角色:抽象定义,引用对接口对象的引用. 重新 ...