bzoj 1500 [NOI 2005] 维修数列
题目大意不多说了
貌似每个苦逼的acmer都要做一下这个splay树的模版题目吧
还是有很多操作的,估计够以后当模版了。。。。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath> using namespace std;
const int N = ;
const int INF = 0x3f3f3f3f;
#define ls ch[x][0]
#define rs ch[x][1] struct SplayTree{
int ch[N][] , pre[N];
int ml[N] , mr[N] , mm[N]; //区间最大
int val[N] , sz[N] , sum[N] , size , rt;
int rev[N] , to[N]; // lazy标记
int del[N] , top; //内部保存删除的数的位置,然后可以从其中提取位置给新进入的元素
int a[N]; void push_up(int x)
{
sz[x] = sz[ls]+sz[rs]+;
sum[x] = sum[ls]+sum[rs]+val[x];
/*********************/
ml[x] = max(ml[ls] , sum[ls]+val[x]+max(ml[rs] , ));
mr[x] = max(mr[rs] , sum[rs]+val[x]+max(mr[ls] , ));
mm[x] = max(mm[ls] , max(mm[rs] , max(ml[rs],)+max(mr[ls],)+val[x]));
/*********************/
} void push_down(int x)
{
if(rev[x]){
if(ls){
rev[ls]^= ;
swap(ml[ls] , mr[ls]);
}
if(rs){
rev[rs]^= ;
swap(ml[rs] , mr[rs]);
}
swap(ls , rs);
rev[x] = ;
}
/**to[x]的初始化要注意**/
if(to[x]!=-INF){
if(ls){
sum[ls] = sz[ls]*to[x];
ml[ls] = mr[ls] = mm[ls] = max(sum[ls] , to[x]);
val[ls] = to[ls] = to[x];
}
if(rs){
sum[rs] = sz[rs]*to[x];
ml[rs] = mr[rs] = mm[rs] = max(sum[rs] , to[x]);
val[rs] = to[rs] = to[x];
}
to[x] = -INF;
}
} void newNode(int &x , int fa , int v)
{
if(top != -)
x = del[top--];
else x = ++size;
ch[x][] = ch[x][] = ;
pre[x] = fa;
val[x] = v , sz[x] = ;
sum[x] = ml[x] = mr[x] = mm[x] = val[x];
rev[x] = , to[x] = -INF;
} void build(int &x , int l , int r , int fa)
{
if(l>r) return;
int m=(l+r)>>;
newNode(x , fa , a[m]);
build(ls , l , m- , x);
build(rs , m+ , r , x);
push_up(x);
} void init(int n)
{
/*****因为所有点的最终叶子节点都下标设为了0,所以0上的数据要不影响整棵树*****/
sz[] = sum[] = ch[][] = ch[][] = val[] = pre[] = ;
to[] = ml[] = mr[] = mm[] = -INF;
rev[] = ;
top = - , rt = size = ;
newNode(rt , , -INF);
newNode(ch[rt][] , rt , -INF);
build(ch[ch[rt][]][] , , n , ch[rt][]);
push_up(ch[rt][]);
push_up(rt);
} void Rotate(int x , int f)
{
int y=pre[x] , z=pre[y];
/**y要旋转到下方,下传lazy标记**/
push_down(y);
ch[y][!f] = ch[x][f] , pre[ch[x][f]] = y;
ch[x][f] = y , pre[y] = x;
ch[z][ch[z][]==y] = x , pre[x]=z;
push_up(y);
push_up(x);
} void Splay(int x , int goal)
{
while(pre[x] != goal){
if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][]==x);
else{
int y = pre[x] , z = pre[y];
int f = ch[z][] == y;
if(ch[y][f] == x) Rotate(x , !f);
else Rotate(y,f);
Rotate(x , f);
}
}
push_up(x);
if(goal == ) rt = x;
} int Select(int pos)
{
int x = rt;
push_down(x);
while(sz[ls]+ != pos){
if(sz[ls]+>pos) x=ls;
else{
pos = pos-sz[ls]-;
x = rs;
}
push_down(x);
}
return x;
}
/***从pos位置之后插入cnt个值***/
void Insert(int pos , int cnt)
{
int x = Select(pos);
Splay(x , );
int y = Select(pos+);
Splay(y , x);
build(ch[y][] , , cnt , y);
/***这里build将a[1~cnt]插入到splay树中,要push_up更新***/
push_up(y);
push_up(x);
}
/***回收被删除的数的位置***/
void Recycle(int x)
{
if(x){
del[++top]=x;
Recycle(ls);
Recycle(rs);
}
} void Delete(int s , int t)
{
int x = Select(s-) , y = Select(t+);
Splay(x , ) , Splay(y , x);
Recycle(ch[y][]);
ch[y][] = ;
/***这里y的左子树删除,明显子树数据改变,所以要重新push_up更新数据***/
push_up(y);
push_up(x);
}
/****将s~t区间内的所有值都修改为v****/
void update(int s , int t , int v)
{
int x = Select(s-) , y = Select(t+);
Splay(x , ) , Splay(y , x);
int ptr = ch[y][];
to[ptr]=v;
val[ptr]=v;
sum[ptr]=v*sz[ptr];
ml[ptr] = mr[ptr] = mm[ptr] = max(sum[ptr] , v);
return ;
} void Reverse(int s , int t)
{
int x = Select(s-) , y = Select(t+);
Splay(x , ) , Splay(y , x);
int ptr = ch[y][];
rev[ptr]^=;
swap(ml[ptr] , mr[ptr]);
} int querySum(int s , int t)
{
int x = Select(s-) , y = Select(t+);
// cout<<"x: "<<x<<" y: "<<y<<endl;
Splay(x , ) , Splay(y , x);
return sum[ch[y][]];
} int queryMax()
{
int x = Select() , y = Select(sz[rt]);
Splay(x , ) , Splay(y , x);
return mm[ch[y][]];
}
}spt;
int main()
{
// freopen("a.in" , "r" , stdin);
int n , m;
char str[] ;
int s , t , v , pos , k;
while(~scanf("%d%d" , &n , &m))
{
for(int i= ; i<=n ; i++) scanf("%d" , &spt.a[i]);
spt.init(n);
/*
for(int i=0 ; i<=spt.size ; i++){
cout<<"i: "<<i<<" sum: "<<spt.sum[i]<<" l: "<<spt.ch[i][0]<<" lv: "<<spt.val[spt.ch[i][0]]<<" r: "<<spt.ch[i][1]<<" rv: "<<spt.val[spt.ch[i][1]]<<endl;
}*/
for(int i= ; i<m ; i++){
scanf("%s" , str);
if(str[] == 'I'){
scanf("%d%d" , &pos , &k);
for(int i= ; i<=k ; i++) scanf("%d" , &spt.a[i]);
spt.Insert(pos+ , k);
}
else if(str[]=='D'){
scanf("%d%d" , &pos , &k);
spt.Delete(pos+ , pos+k);
}
else if(str[] == 'M' && str[] == 'K'){
scanf("%d%d%d" , &pos , &k , &v);
spt.update(pos+ , pos+k , v);
}
else if(str[] == 'R'){
scanf("%d%d" , &pos , &k);
spt.Reverse(pos+ , pos+k);
}
else if(str[] == 'G'){
scanf("%d%d" , &pos , &k);
printf("%d\n" , spt.querySum(pos+ , pos+k));
}
else{
/****这里不能直接用spt.mm[rt]作为答案,因为为了方便查询,
我们增加了两个不包含在本身数组的点,直接spt.mm[rt]会把这两个点也算进来***/
printf("%d\n" , spt.queryMax());
}
}
}
return ;
}
bzoj 1500 [NOI 2005] 维修数列的更多相关文章
- 洛谷 2042 BZOJ 1500 NOI 2005 维护数列
[题意概述] 维护一个数列,要求支持以下6种操作: [题解] 大Boss...可以用Treap解决 需要用到垃圾回收.线性建树. #include<cstdio> #include< ...
- BZOJ 1500/Luogu 2042 - 维修数列 - [NOI2005][Splay]
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1500 题目链接:https://www.luogu.org/problemnew/sho ...
- NOI 2005 维修数列
妈妈呀我终于过了!!!原来是数据坑我!!! 弃疗弃疗弃疗弃疗!!!!我调了一天呢....被GET_SUM 8 0打败了.... 啥也不说了....还是我太年轻.... 更新了一下常数,跑的还是可以的: ...
- NOI 2005维护数列
题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...
- bzoj 1500: [NOI2005]维修数列 splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 6556 Solved: 1963[Submit][Status ...
- [BZOJ 1500] [NOI2005] 维修数列
题目链接:BZOJ - 1500 题目分析 我要先说一下,这道题我写了一晚上,然后Debug了一整个白天..........再一次被自己的蒟蒻程度震惊= = 这道题是传说中的Splay维护数列的Bos ...
- [BZOJ 1500]维修数列 [Splay Tree从进阶到住院]
历尽艰辛终于A掉了这题QwQ 贴COGS评论区几句话=.= 策爷:"splay/块状链表的自虐题.".深刻理解到如果没有M倾向就不要去写这题了.. -Chenyao2333 记得b ...
- BZOJ 1500: [NOI2005]维修数列 (splay tree)
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 4229 Solved: 1283[Submit][Status ...
- 【BZOJ】1500: [NOI2005]维修数列
[算法]splay [题解]数据结构 感谢Occult的模板>_<:HYSBZ 1500 维修数列 #include<cstdio> #include<cctype> ...
随机推荐
- Suricata产生的数据存储目录
不多说,直接上干货! 我这里呢,分两种常用的Suricata. 一.源码编译安装的Suricata 这里不多说,大家可以去看我下面写的博客 使用 Suricata 进行入侵监控(一个简单小例子访问百度 ...
- EventBus 报“Subscriber class already registered to event class”错误
这句子的话意思也很容易理解,“接收者类已经被注册为事件类了”. 之前我是这么写: 事件注册是写在onStart()里面的 @Override protected void onStart() { su ...
- EEPROM介绍
EEPROM( Electrically Erasable Programmable Read Only Memory )全称是电气可擦除可编程只读存储器,是非易失存储器,可以访问到每个字节,容量比较 ...
- elf 文件
objdump 文件名 readelf 文件名
- javascript innerHTML 大数据量加载 导致IE 内存溢出 的解决办法
在做 ajax 滚动加载的时候,越到后面 数据量越大,使用obj.innerHTML+=row添加到页面的时候,出现ie内存不足的情况,此时使用createDocumentFragment,创建一个文 ...
- php-PHP Warning: PHP Startup: Invalid library (maybe not a PHP library) 'xxx.so' in Unknown on line 0
关于xxx.so,今天在安装php的模块时候老是报,xxx.so的问题,虽然不影响使用,但作为一名当年的程序员强迫症患者,誓死要把 他搞清楚,后面发现是删除了也没有影响,因为在安装php的时候已经将他 ...
- Apache安装和文件配置
Apache和Tomcat的区别是:静态文件和动态页面,C++和Java的区别. 对比.
- DROP DATABASE - 删除一个数据库
SYNOPSIS DROP DATABASE name DESCRIPTION 描述 DROP DATABASE 删除一个现存数据库的目录入口并且删除包含数据的目录. 只有数据库所有者能够执行这条命令 ...
- JavaEE-03 JSP数据交互02
学习要点 application pageContext JSP对象作用域 cookie application 作用 类似于系统的“全局变量”,用于在同一个服务器内的所有用于之间的数据共享,对于整个 ...
- linux(Ubuntu/Centos) iproute 路由IP地址等命令集合,查看端口链接
原 linux(Ubuntu/Centos) iproute 路由IP地址等命令集合,查看端口链接 2017年03月20日 16:55:57 风来了- 阅读数:2291 标签: centoslinux ...