NOI2005 维护数列(splay)
学了半天平衡树,选择了一道题来写一写,发现题目是裸的splay模板,但是还是写不好,这个的精髓之处在于在数列的某一个位置加入一个数列,类似于treap里面的merge,然后还学到了题解里面的的回收空间做法,利用时间换取空间也是一种非常不错的做法,由于题目中有区间翻转的操作,所以只能用splay来写,然后对于一些区间最大值和区间最大子序列的询问我们可以用类似于线段树的合并操作来维护,总的来说这是一道对于树形数据结构非常好的运用的题目。——by VANE
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e6+;
int n,m,rt,cnt;
int a[N],id[N],fa[N],c[N][];
int sum[N],sz[N],v[N],mx[N],lx[N],rx[N];
bool tag[N],rev[N];
queue<int> q;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>'') {if(ch=='-') f=-f; ch=getchar();}
while(ch>=''&&ch<='') {x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void pushup(int x)
{
int l=c[x][],r=c[x][];
sum[x]=sum[l]+sum[r]+v[x];
sz[x]=sz[l]+sz[r]+;
mx[x]=max(mx[l],max(mx[r],rx[l]+v[x]+lx[r]));
lx[x]=max(lx[l],sum[l]+v[x]+lx[r]);
rx[x]=max(rx[r],sum[r]+v[x]+rx[l]);
}
inline void pushdown(int x)
{
int l=c[x][],r=c[x][];
if(tag[x])
{
rev[x]=tag[x]=;
if(l) tag[l]=,v[l]=v[x],sum[l]=v[x]*sz[l];
if(r) tag[r]=,v[r]=v[x],sum[r]=v[x]*sz[r];
if(v[x]>=)
{
if(l) lx[l]=rx[l]=mx[l]=sum[l];
if(r) lx[r]=rx[r]=mx[r]=sum[r];
}
else
{
if(l) lx[l]=rx[l]=,mx[l]=v[x];
if(r) lx[r]=rx[r]=,mx[r]=v[x];
}
}
if(rev[x])
{
rev[x]=;rev[l]^=;rev[r]^=;
swap(lx[l],rx[l]);swap(lx[r],rx[r]);
swap(c[l][],c[l][]);swap(c[r][],c[r][]);
}
}
inline void rotate(int x,int &k)
{
int y=fa[x],z=fa[y],l=(c[y][]==x),r=l^;
if(y==k) k=x;else c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
inline void splay(int x,int &k)
{
while(x!=k)
{
int y=fa[x],z=fa[y];
if(y!=k)
{
if(c[z][]==y ^ c[y][]==x) rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
inline int find(int x,int rk)
{
pushdown(x);
int l=c[x][],r=c[x][];
if(sz[l]+==rk) return x;
if(sz[l]>=rk) return find(l,rk);
return find(r,rk-sz[l]-);
}
inline void recycle(int x)
{
int &l=c[x][],&r=c[x][];
if(l) recycle(l);
if(r) recycle(r);
q.push(x);
fa[x]=l=r=tag[x]=rev[x]=;
}
inline int split(int k,int tot)
{
int x=find(rt,k),y=find(rt,k+tot+);
splay(x,rt);splay(y,c[x][]);
return c[y][];
}
inline void query(int k,int tot)
{
int x=split(k,tot);
printf("%d\n",sum[x]);
}
inline void modify(int k,int tot,int val)
{
int x=split(k,tot),y=fa[x];
v[x]=val;tag[x]=;sum[x]=sz[x]*val;
if(val>=) lx[x]=rx[x]=mx[x]=sum[x];
else lx[x]=rx[x]=,mx[x]=val;
pushup(y);pushup(fa[y]);
}
inline void rever (int k,int tot)
{
int x=split(k,tot),y=fa[x];
if(!tag[x])
{
rev[x]^=;
swap(c[x][],c[x][]);
swap(lx[x],rx[x]);
pushup(y);pushup(fa[y]);
}
}
inline void erase(int k,int tot)
{
int x=split(k,tot),y=fa[x];
recycle(x);c[y][]=;
pushup(y);pushup(fa[y]);
}
inline void build(int l,int r,int f)
{
int mid=l+r>>,now=id[mid],pre=id[f];
if(l==r)
{
mx[now]=sum[now]=a[l];
lx[now]=rx[now]=max(a[l],);
sz[now]=;
}
if(l<mid) build(l,mid-,mid);
if(mid<r) build(mid+,r,mid);
v[now]=a[mid];fa[now]=pre;
pushup(now);
c[pre][mid>=f]=now;
}
inline void insert(int k,int tot)
{
for(int i=;i<=tot;++i) a[i]=read();
for(int i=;i<=tot;++i)
{
if(!q.empty()) id[i]=q.front(),q.pop();
else id[i]=++cnt;
}
build(,tot,);
int z=id[+tot>>];
int x=find(rt,k+),y=find(rt,k+);
splay(x,rt);splay(y,c[x][]);
fa[z]=y;c[y][]=z;
pushup(y);pushup(x);
}
int main()
{
n=read();m=read();
mx[]=a[]=a[n+]=-inf;
for(int i=;i<=n;++i) a[i+]=read();
for(int i=;i<=n+;++i) id[i]=i;
build(,n+,);
rt=n+>>;cnt=n+;
int k,tot,val;char ch[];
while(m--)
{
scanf("%s",ch);
if(ch[]!='M'||ch[]!='X') k=read(),tot=read();
if(ch[]=='I') insert(k,tot);
if(ch[]=='D') erase(k,tot);
if(ch[]=='M')
{
if(ch[]=='X') printf("%d\n",mx[rt]);
else val=read(),modify(k,tot,val);
}
if(ch[]=='R') rever(k,tot);
if(ch[]=='G') query(k,tot);
}
}
NOI2005 维护数列(splay)的更多相关文章
- P2042 [NOI2005]维护数列 && Splay区间操作(四)
到这里 \(A\) 了这题, \(Splay\) 就能算入好门了吧. 今天是个特殊的日子, \(NOI\) 出成绩, 大佬 \(Cu\) 不敢相信这一切这么快, 一下子机房就只剩我和 \(zrs\) ...
- 洛谷 P2042 [NOI2005]维护数列-Splay(插入 删除 修改 翻转 求和 最大的子序列)
因为要讲座,随便写一下,等讲完有时间好好写一篇splay的博客. 先直接上题目然后贴代码,具体讲解都写代码里了. 参考的博客等的链接都贴代码里了,有空再好好写. P2042 [NOI2005]维护数列 ...
- P2042 [NOI2005]维护数列[splay或非旋treap·毒瘤题]
P2042 [NOI2005]维护数列 数列区间和,最大子列和(必须不为空),支持翻转.修改值.插入删除. 练码力的题,很毒瘤.个人因为太菜了,对splay极其生疏,犯了大量错误,在此记录,望以后一定 ...
- 洛谷.2042.[NOI2005]维护数列(Splay)
题目链接 2017.12.24 第一次写: 时间: 2316ms (1268ms) 空间: 19.42MB (19.5MB)(O2) 注:洛谷测的时间浮动比较大 /* 插入一段数:将这些数先单独建一棵 ...
- BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay)
手动博客搬家: 本文发表于20180825 00:34:49, 原地址https://blog.csdn.net/suncongbo/article/details/82027387 题目链接: (l ...
- 数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列
339. [NOI2005] 维护数列 时间限制:3 s 内存限制:256 MB [问题描述] 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际 ...
- [NOI2005]维护数列(区间splay)
[NOI2005]维护数列(luogu) 打这玩意儿真是要了我的老命 Description 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文 ...
- [NOI2005] 维护数列
[NOI2005] 维护数列 题目 传送门 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 操作编号 输入文件中的格式 说明 1 ...
- Luogu P2042 [NOI2005]维护数列(平衡树)
P2042 [NOI2005]维护数列 题意 题目描述 请写一个程序,要求维护一个数列,支持以下\(6\)种操作:(请注意,格式栏中的下划线'_'表示实际输入文件中的空格) 输入输出格式 输入格式: ...
随机推荐
- 【BZOJ】1355 [Baltic2009]Radio Transmission
[算法]KMP [题解]KMP中n-next[n]得到最小循环节的性质. 考虑一个循环串(最后一个循环节可能残缺),它最长的[后缀=前缀]一定是以第二个循环节为起始位置的后缀. 正着考虑的话假设后缀T ...
- struts入门
1.概念
- C#开发微信公众平台开发-微信海报介绍和开发流程
“让客户发展客户”,微信海报才是微信公众平台最高明的吸粉手段,海报上有粉丝的专属二维码,有粉丝的头像及商户宣传的广告等.新粉丝扫描这个专属二维码会关注公众号,同时分享海报的粉丝会增加积分换取礼品或者优 ...
- caffe Python API 之Model训练
# 训练设置 # 使用GPU caffe.set_device(gpu_id) # 若不设置,默认为0 caffe.set_mode_gpu() # 使用CPU caffe.set_mode_cpu( ...
- angular项目文件概览
在Mac上打开终端,输入ng new b-app 如下: 然后在webstorm中打开 src文件夹 你的应用代码位于src文件夹中. 所有的Angular组件.模板.样式.图片以及你的应用所需的任 ...
- HDFS RAID实现方案(转)
原文链接:http://blog.chinaunix.net/uid-20196318-id-3213700.html 分布式文件系统主要用于解决海量数据存储的问题,如Goolge.Facebook等 ...
- Math类的数学计算功能
//Math类的数学计算功能 public class MathTest { public static void main(String[] args) { /*----------下面是三角运算- ...
- IEnumerable的几个简单用法
咋一看到IEnumerable这个接口,我们可能会觉得很神奇,在一般的编程时,基本上我们是想不到去用它的,可是,俗话说得好,存在便是道理,那么,它对我们来说,能够带来哪些奇妙的事情呢? 要想弄懂它,我 ...
- Django之Cookie、Session和自定义分页
cookie Cookie的由来 大家都知道HTTP协议是无状态的. 无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不 ...
- Mysql修改语句的运行流程
执行修改语句前要先连接数据库,这是连接器的工作. 接下来,分析器会通过词法和语法解析知道这是一条更新语句.优化器决定要使用 ID 这个索引.然后,执行器负责具体执行,找到这一行,然后更新. Mysql ...