【NOI 2005】 维修数列
【题目链接】
【算法】
本题所运用的也是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】 维修数列的更多相关文章
- NOI 2005 维修数列
妈妈呀我终于过了!!!原来是数据坑我!!! 弃疗弃疗弃疗弃疗!!!!我调了一天呢....被GET_SUM 8 0打败了.... 啥也不说了....还是我太年轻.... 更新了一下常数,跑的还是可以的: ...
- bzoj 1500 [NOI 2005] 维修数列
题目大意不多说了 貌似每个苦逼的acmer都要做一下这个splay树的模版题目吧 还是有很多操作的,估计够以后当模版了.... #include <cstdio> #include < ...
- NOI 2005维护数列
题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...
- 洛谷 2042 BZOJ 1500 NOI 2005 维护数列
[题意概述] 维护一个数列,要求支持以下6种操作: [题解] 大Boss...可以用Treap解决 需要用到垃圾回收.线性建树. #include<cstdio> #include< ...
- 【BZOJ-1500】维修数列 Splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 11047 Solved: 3460[Submit][Statu ...
- [NOI2005] 维修数列
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 8397 Solved: 2530 Description In ...
- bzoj 1500: [NOI2005]维修数列 splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 6556 Solved: 1963[Submit][Status ...
- [BZOJ1500][NOI2005]维修数列---解题报告
Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...
- [BZOJ 1500]维修数列 [Splay Tree从进阶到住院]
历尽艰辛终于A掉了这题QwQ 贴COGS评论区几句话=.= 策爷:"splay/块状链表的自虐题.".深刻理解到如果没有M倾向就不要去写这题了.. -Chenyao2333 记得b ...
- 【BZOJ1500】【NOI2005】维修数列(Splay)
[BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...
随机推荐
- Java中的类反射
一.反射的概念 : 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序 ...
- centos6安装概述
1.1.选择安装类型:[Install or upgrade an existing system]安装或升级现有系统 1.2.介质校验:[Skip]跳过介质校验,校验时间较长 1.3.语言选择:[E ...
- Spring实战Day6
3.4 bean的作用域 Spring中bean的作用域 单例(Singleton):在整个应用中,只创建bean的一个实例. 原型(Prototype):每次注入或者通过Spring应用上下文获取的 ...
- 问题:typedef char *pstring????
typedef char *pstring; const pstring cstr = 0; //cstr是指向char的常量指针: const pstring *ps; //ps是一个指针,它的对象 ...
- Intent传递简单对象与集合
我们在Intent传递传递对象.能够有三种方式,实现Serializable接口.实现Parcelable接口,使用json格式序列化与反序列化. 在此我们使用第二方式,现实Parcelable接口, ...
- 前端高频面试题 JavaScript篇
以下问题都来自于互联网前端面经分享,回答为笔者通过查阅资料加上自身理解总结,不保证解答的准确性,有兴趣讨论的同学可以留言或者私信讨论. 1.JS的异步机制? 2.闭包如何实现? 3.原型链.继承? 4 ...
- TraceTool 跟踪工具的瑞士军刀(C++版使用)
TraceTool查看器能够显示多种类型的来源(从提供的框架.日志文件.事件日志.或者OutputDebugString方法).一个简单而强大的client框架发送简单的跟踪,分组跟踪.类和对象浏览器 ...
- weex 小结
1. import 文件时,必须引入全称,不能省略 .vue import mEcharts from '../components/Echarts.vue' 2.weex 的 cli 中没有 配置 ...
- 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂
浅谈JS中的!=.== .!==.===的用法和区别 var num = 1; var str = '1'; var test = 1; test == num //tr ...
- 不能选择sublime作为默认打开方式的解决办法
Sublime Text 绿色版删除后无法设置为默认打开方式…而且网上也没有给出明确的解决办法 注册表的解决办法: 删除 HKEY_CURRENT_USER\Software\Classes\Appl ...