【题目链接】

点击打开链接

【算法】

本题所运用的也是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. Codeforces 552E Vanya and Brackets(枚举 + 表达式计算)

    题目链接 Vanya and Brackets 题目大意是给出一个只由1-9的数.乘号和加号组成的表达式,若要在这个表达式中加上一对括号,求加上括号的表达式的最大值. 我们发现,左括号的位置肯定是最左 ...

  2. 通过quick2wire使用raspi的i2c和ks103通信

    原文:http://www.cnblogs.com/hangxin1940/archive/2013/04/04/2999015.html 之前介绍了如何启用i2c设备 http://www.cnbl ...

  3. 用canal监控binlog并实现mysql定制同步数据的功能

    业务背景 写任何工具都不能脱离实际业务的背景.开始这个项目的时候是因为现有的项目中数据分布太零碎,零零散散的分布在好几个数据库中,没有统一的数据库来收集这些数据.这种情况下想做一个大而全的会员中心系统 ...

  4. Java 5/Java 6/Java7/Java 8新特性收集

    前言: Java 8对应的JDK版本为JDK8,而官网下载回来安装的时候,文件夹上写的是JDK1.8,同一个意思.(而这个版本命名也是有规律的,以此类推) 一.Java 5 1.https://seg ...

  5. SSD S.M.A.R.T

    经过多年HDD硬盘厂商的完善,S.M.A.R.T已经形成了一些标准,但对于SSD来说,大多数S.M.A.R.T都是自定义的,以至于每个厂商所提供的参数并不一致,但大体都会参考HDD S.M.A.R.T ...

  6. logistics regression

    logistics regression用于解决一些二分类问题.比如(纯假设)网上购物时,网站会判断一个人退货的可能性有多大,如果该用户退货的可能性很大,那么网站就不会推荐改用户购买退费险.反之,如果 ...

  7. 【Hibernate】(2)Hibernate配置与session、transaction

    1. Hibernate经常使用配置 使用hibernate.default_schema属性能够让全部生成的表都带一个指定的前缀. 2. session简单介绍 不建议直接使用jdbc的connec ...

  8. HTML5面试题-b

    感谢分享 面试有几点需要注意: 面试题目: 根据你的等级和职位变化,入门级到专家级:范围↑.深度↑.方向↑. 题目类型: 技术视野.项目细节.理论知识型题,算法题,开放性题,案例题. 进行追问: 可以 ...

  9. 杭电 2176 取(m堆)石子游戏(博弈)

    取(m堆)石子游戏 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  10. 把握linux内核设计思想(五):下半部机制之工作队列及几种机制的选择

    [版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途]         工作队列是下半部的第二种将工作推后运行形式.和软中断.task ...