【题目链接】

点击打开链接

【算法】

本题所运用的也是Splay的区间操作,但是实现较为困难

INSERT操作

            将pos splay至根节点,pos+1 splay至根节点的右节点,然后对根节点的右节点的左节点建树即可

DELETE操作

            将l-1 splay至根节点, r+1 splay至根节点的右节点,直接“砍断”根节点的右节点的左节点

MAKE_SAME操作

            将l-1 splay至根节点,r+1 splay至根节点的右节点,给根节点的右节点的左节点打上标记

REVERSE操作

            将l-1 splay至根节点,r+1 splay至根节点的右节点,给根节点的右节点的左节点打上标记

GET_SUM操作

            将l-1 splay至根节点,r+1 splay至根节点的右节点,直接输出根节点的右节点的左节点的sum

MAX_SUM操作

            此操作的实现类似于树形DP :

我们不妨给每个节点增加三个域

lmax :从这个节点所代表的区间的左端点开始向右延伸的最大和

rmax :从这个节点所代表的区间的右端点开始像左延伸的最大和

max : 该节点所代表区间的最大连续子段和

那么,lmax该如何取值?

令根节点为root,根节点的左儿子为lc,根节点的右儿子为rc

            我们可以分情况讨论 :

lmax[root]不包括root,lmax[root] = lmax[lc]

            lmax[root]包括root,那么 : 若不向右继续延伸,则lmax[root] = tot[lc] + val[root],若向右延伸,

lmax[root] = tot[lc] + val[root] + lmax[rc]

            我们只要在这三者中取最大值就可以了

rmax同理

那么,max又该如何取值呢?

我们还是分情况讨论 :

令根节点为root,根节点的左儿子为rc,根节点的右儿子为rc

max[root]不包括root,max[root] = max{max[lc],max[rc]}

            max[root]包括root,那么 : 若不向右也不向左延伸,则max[root] = val[root],若向左延伸,

max[root] = val[root] + rmax[lc]

            若向右延伸,则 :

max[root] = val[root] + lmax[rc]

            若两边同时延伸,则 :

max[root] = val[root] + rmax[rc] + lmax[lc]

            只需在这五者中取最大值即可

关于内存池 :

            由于本题数据量较大,我们要进行内存回收,内存回收方法如下 :

我们建立一个内存池,开始时将所有可用空间都放入内存池,插入一个节点时,我们从内存池弹出一个节点,

分配给这个节点,删除时,我们将要删除的节点放回内存池,如果是删除一棵子树,则将整棵子树放回内存池

这个内存池可以用栈,队列,链表等许多数据结构来维护,笔者选用的是栈,由于维护方法比较简单,笔者不再赘述

【代码】

本题的细节很多,写代码时一定要严谨!

#include<bits/stdc++.h>
using namespace std;
#define MAXN 20000
#define MAXX 500000
const int INF = 2e9; int i,N,M,tot,pos,val;
int a[MAXX+];
char opt[];
stack<int> stk; template <typename T> inline void read(T &x) {
int f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
for (; isdigit(c); c = getchar()) x = x * + c - '';
x *= f;
} template <typename T> inline void write(T x) {
if (x < ) { putchar('-'); x = -x; }
if (x > ) write(x/);
putchar(x%+'');
} template <typename T> inline void writeln(T x) {
write(x);
puts("");
} struct Splay {
int root;
struct Node {
int fa,son[],size,lmax,rmax,tot,
Max,val,lazy;
bool rev;
} Tree[MAXX+];
inline bool get(int x) {
return Tree[Tree[x].fa].son[] == x;
}
inline void build(int index,int l,int r) {
int id,mid;
mid = (l + r) >> ;
Tree[index].lazy = INF;
Tree[index].rev = ;
Tree[index].val = a[mid];
if (l == r) {
Tree[index].size = ;
Tree[index].lmax = Tree[index].rmax = Tree[index].Max = Tree[index].tot = a[mid];
return;
}
if (l < mid) {
id = stk.top();
stk.pop();
Tree[index].son[] = id;
Tree[id].fa = index;
build(id,l,mid-);
}
if (mid < r) {
id = stk.top();
stk.pop();
Tree[index].son[] = id;
Tree[id].fa = index;
build(id,mid+,r);
}
update(index);
}
inline void update(int index) {
if (!index) return;
Tree[index].tot = Tree[Tree[index].son[]].tot + Tree[Tree[index].son[]].tot + Tree[index].val;
Tree[index].size = Tree[Tree[index].son[]].size + Tree[Tree[index].son[]].size + ;
Tree[index].lmax = max(Tree[Tree[index].son[]].lmax,Tree[Tree[index].son[]].tot+max(Tree[Tree[index].son[]].lmax,)+Tree[index].val);
Tree[index].rmax = max(Tree[Tree[index].son[]].rmax,Tree[Tree[index].son[]].tot+max(Tree[Tree[index].son[]].rmax,)+Tree[index].val);
Tree[index].Max = max(Tree[Tree[index].son[]].Max,max(Tree[Tree[index].son[]].Max,Tree[index].val+max(Tree[Tree[index].son[]].rmax,)+max(Tree[Tree[index].son[]].lmax,)));
}
inline void pushdown(int index) {
int tmp;
if (Tree[index].lazy != INF) {
tmp = Tree[index].lazy;
Tree[index].lazy = INF;
if (Tree[index].son[]) Tree[Tree[index].son[]].tot = Tree[Tree[index].son[]].size * tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].tot = Tree[Tree[index].son[]].size * tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].val = tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].val = tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].lmax = Tree[Tree[index].son[]].rmax = Tree[Tree[index].son[]].Max = max(tmp,Tree[Tree[index].son[]].size*tmp);
if (Tree[index].son[]) Tree[Tree[index].son[]].lmax = Tree[Tree[index].son[]].rmax = Tree[Tree[index].son[]].Max = max(tmp,Tree[Tree[index].son[]].size*tmp);
if (Tree[index].son[]) Tree[Tree[index].son[]].lazy = tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].lazy = tmp;
}
if (Tree[index].rev) {
swap(Tree[index].son[],Tree[index].son[]);
swap(Tree[Tree[index].son[]].lmax,Tree[Tree[index].son[]].rmax);
swap(Tree[Tree[index].son[]].lmax,Tree[Tree[index].son[]].rmax);
Tree[Tree[index].son[]].rev ^= ;
Tree[Tree[index].son[]].rev ^= ;
Tree[index].rev = ;
}
}
inline int query_pos(int x) {
int index = root;
while (true) {
pushdown(index);
if (x > Tree[Tree[index].son[]].size) {
x -= Tree[Tree[index].son[]].size;
if (x == ) return index;
--x;
index = Tree[index].son[];
} else index = Tree[index].son[];
}
}
inline void clear(int index) {
Tree[Tree[index].fa].son[get(index)] = ;
Tree[index].fa = ;
stk.push(index);
if (Tree[index].son[]) clear(Tree[index].son[]);
if (Tree[index].son[]) clear(Tree[index].son[]);
}
inline void Insert(int index) {
int id;
int x = query_pos(index),
y = query_pos(index+);
splay(x,); splay(y,root);
id = stk.top();
stk.pop();
build(id,,tot);
Tree[Tree[root].son[]].son[] = id;
Tree[id].fa = Tree[root].son[];
update(Tree[root].son[]);
update(root);
}
inline void rotate(int x) {
int f = Tree[x].fa,g = Tree[f].fa,
tmpx = get(x),tmpf = get(f);
pushdown(f); pushdown(x);
if (!f) return;
Tree[f].son[tmpx] = Tree[x].son[tmpx^];
if (Tree[x].son[tmpx^]) Tree[Tree[x].son[tmpx^]].fa = f;
Tree[x].son[tmpx^] = f;
Tree[f].fa = x;
Tree[x].fa = g;
if (g) Tree[g].son[tmpf] = x;
update(f);
update(x);
}
inline void splay(int x,int pos) {
int f;
for (f = Tree[x].fa; (f = Tree[x].fa) != pos; rotate(x)) {
if (Tree[f].fa != pos)
rotate(get(f) == get(x) ? (f) : (x));
}
if (!pos) root = x;
}
inline void modify(int l,int r,int v) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
int tmp = Tree[Tree[root].son[]].son[];
Tree[tmp].val = Tree[tmp].lazy = v;
Tree[tmp].tot = v * Tree[tmp].size;
Tree[tmp].lmax = Tree[tmp].rmax = Tree[tmp].Max = max(Tree[tmp].size*v,v);
update(Tree[root].son[]);
update(root);
}
inline void reverse(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
Tree[Tree[Tree[root].son[]].son[]].rev ^= ;
swap(Tree[Tree[Tree[root].son[]].son[]].lmax,Tree[Tree[Tree[root].son[]].son[]].rmax);
}
inline void erase(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
clear(Tree[Tree[root].son[]].son[]);
Tree[Tree[root].son[]].son[] = ;
update(Tree[root].son[]);
update(root);
}
int get_sum(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
return Tree[Tree[Tree[root].son[]].son[]].tot;
}
int max_sum(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
return Tree[Tree[Tree[root].son[]].son[]].Max;
}
} T; int main() { read(N); read(M); for (i = ; i <= MAXX; i++) stk.push(i); a[] = a[N+] = -INF;
for (i = ; i <= N + ; i++) read(a[i]); T.Tree[].lmax = T.Tree[].rmax = T.Tree[].Max = -INF;
T.root = ;
T.build(,,N+); while (M--) {
scanf("%s",&opt);
if (opt[] == 'I') {
read(pos); read(tot);
for (i = ; i <= tot; i++) read(a[i]);
T.Insert(pos+);
N += tot;
} else if (opt[] == 'D') {
read(pos); read(tot);
T.erase(pos+,pos+tot);
N -= tot;
} else if (opt[] == 'M' && opt[] == 'K') {
read(pos); read(tot); read(val);
T.modify(pos+,pos+tot,val);
} else if (opt[] == 'R') {
read(pos); read(tot);
T.reverse(pos+,pos+tot);
} else if (opt[] == 'G') {
read(pos); read(tot);
writeln(T.get_sum(pos+,pos+tot));
} else if (opt[] == 'M' && opt[] == 'X') {
writeln(T.max_sum(,N+));
}
} return ; }

【NOI 2005】 维修数列的更多相关文章

  1. NOI 2005 维修数列

    妈妈呀我终于过了!!!原来是数据坑我!!! 弃疗弃疗弃疗弃疗!!!!我调了一天呢....被GET_SUM 8 0打败了.... 啥也不说了....还是我太年轻.... 更新了一下常数,跑的还是可以的: ...

  2. bzoj 1500 [NOI 2005] 维修数列

    题目大意不多说了 貌似每个苦逼的acmer都要做一下这个splay树的模版题目吧 还是有很多操作的,估计够以后当模版了.... #include <cstdio> #include < ...

  3. NOI 2005维护数列

    题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...

  4. 洛谷 2042 BZOJ 1500 NOI 2005 维护数列

    [题意概述] 维护一个数列,要求支持以下6种操作: [题解] 大Boss...可以用Treap解决 需要用到垃圾回收.线性建树. #include<cstdio> #include< ...

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

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

  6. [NOI2005] 维修数列

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 8397  Solved: 2530 Description In ...

  7. bzoj 1500: [NOI2005]维修数列 splay

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6556  Solved: 1963[Submit][Status ...

  8. [BZOJ1500][NOI2005]维修数列---解题报告

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

  9. [BZOJ 1500]维修数列 [Splay Tree从进阶到住院]

    历尽艰辛终于A掉了这题QwQ 贴COGS评论区几句话=.= 策爷:"splay/块状链表的自虐题.".深刻理解到如果没有M倾向就不要去写这题了.. -Chenyao2333 记得b ...

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

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

随机推荐

  1. ASP.NET Core 如何记录每次请求的Request信息 - sky 胡萝卜星星 - CSDN博客

    原文:ASP.NET Core 如何记录每次请求的Request信息 - sky 胡萝卜星星 - CSDN博客 版权声明:本文为starfd原创文章,转载请标明出处. https://blog.csd ...

  2. Android PullToRefresh 下拉刷新,上拉很多其它,支持ScrollView,ListView,可方便拓展GridView,WebView等

    在写着东西之前.从网上找到非常多这方面的源代码,可是基本没有找到惬意的.包含在GitHub上的比較有名的Android-PullToRefresh-master.思来想去还是自己写吧.当然当中借鉴了一 ...

  3. Win10 LTSB版本安装

    win10 LTSB版本可以看作是 win10的阉割版,没有了几乎用不到还占资源的应用商店.小娜.没有了 EDGE只有IE11....云云 下载地址  https://msdn.itellyou.cn ...

  4. 跟着实例学习设计模式(7)-原型模式prototype(创建型)

    原型模式是创建型模式. 设计意图:用原型实例指定创建对象的类型,并通过拷贝这个原型来创建新的对象. 我们使用构建简历的样例的类图来说明原型模式. 类图: 原型模式主要用于对象的复制.它的核心是就是类图 ...

  5. Intel Edison —— 控制GPIO接口,网页显示传感器数值

    前言 原创文章,转载引用务必注明链接. 因为是使用Typora(markdown)写好然后复制到论坛的,推荐直接访问我的网站以获得更好地阅读体验. Intel XDK IoT 开发环境很久之前就上手了 ...

  6. android项目笔记(一)

    1.getInstance:单例模式创建类的实例,getInstance在单例模式(保证一个类仅有一个实例,并提供一个访问它的全局访问点)的类中常见,用来生成唯一的实例,getInstance往往是s ...

  7. HDU 2108 Shape of HDU (判断是不是凸多边形 叉乘)

    Shape of HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  8. vue class与style绑定、条件渲染、列表渲染

    列表渲染 根据我例子的需要,先来说下,列表渲染使用到的是v-for指令,需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名,具体使用方法 ...

  9. mysql语句:SET NAMES UTF8

    一直以来只知道mysql_query("SET NAMES UTF8");是设定数据库编码的,但是一直不清楚“SET NAMES UTF8”是什么. 直到今天才知道 SET NAM ...

  10. C#高阶与初心:(二)P/Invoke平台调用

    最近某个项目要采集交易终端的信息用于监管,主要厂商给出了API,C++版的...开启hard模式!!! C#调用C++的DLL基本就两种方法:加一个VC++项目包一层,或者使用P/Invoke(平台调 ...