洛谷 P2042 【[NOI2005]维护数列】
一直在想要做这道题,但是被那个硕大的Splay标签压垮了
好了,切入正题
这道题应该是我第二次用splay来维护区间问题 我还是太菜了QAQ
其实思路也很简单,就是以每一个位置的下标来进行维护,然后其实就是跟权值树是一模一样的了
然后再具体说一下
为了保证效率,像线段树和文艺平衡树一样,我们可以维护一个\({lazytag}\),然后在需要向下查询时再向下查询就行
然后我们考虑两种标记各自下传的先后顺序
我们可以发现,如果一个区间内已经被“同化”,即进行了\(make-same\)操作,这个时候,翻转也没有了意义。
关于求最大子段和,这个部分就跟原来用线段树解决此类问题是一模一样的,维护一个gss标记,然后对其做DP就行了。
然后这一道题和其他平衡树的题最大的一点不同是它是区间插入,区间删除。为了提升效率,我们可以考虑先将每一次要加入的一段区间预处理成一棵平衡树,然后再直接插入,这样的话效率会有很大的提升
然后,这道题差不多就完了
具体就看代码吧
#pragma G++ optimize(3)
#pragma GCC optimize(3)
#pragma G++ optimize(2)
#pragma GCC optimize(2)
#pragma G++ optimize("-Ofast")
#pragma GCC optimize("-Ofast")
#include<queue>
#include<cstdio>
#include<cstring>
#define dir(p) (son[fa[p]][1]==p)
#define inf 0x3f3f3f
using namespace std;
const int maxn=6e5+10;
char opt[30];
int n,m,ncnt,root;
queue<int>q;
int siz[maxn],son[maxn][2],sum[maxn],val[maxn];
int gss[maxn],lx[maxn],rx[maxn],fa[maxn];
int sam[maxn],rev[maxn],a[maxn],id[maxn];
void swap(int &a,int &b)
{
a^=b^=a^=b;
}
int max(int a,int b)
{
return a>b?a:b;
}
inline int read()
{
register int num=0,f=1;
register char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}
void upd(register int t)
{
int l=son[t][0],r=son[t][1];
siz[t]=siz[l]+siz[r]+1;
sum[t]=sum[l]+sum[r]+val[t];
lx[t]=max(lx[l],sum[l]+val[t]+lx[r]);
rx[t]=max(rx[r],sum[r]+val[t]+rx[l]);
gss[t]=max(rx[l]+lx[r]+val[t],max(gss[l],gss[r]));
}
void pushdown(register int t)
{
int l=son[t][0],r=son[t][1];
if(sam[t])
{
sam[t]=rev[t]=0;
if(l)
{
sam[l]=1,val[l]=val[t];
sum[l]=val[l]*siz[l];
lx[l]=rx[l]=max(sum[l],0);
gss[l]=val[l]<0?val[l]:sum[l];
}
if(r)
{
sam[r]=1,val[r]=val[t];
sum[r]=val[r]*siz[r];
lx[r]=rx[r]=max(sum[r],0);
gss[r]=val[r]<0?val[r]:sum[r];
}
}
if(rev[t])
{
rev[t]=0,rev[l]^=1,rev[r]^=1;
swap(lx[l],rx[l]),swap(rx[r],lx[r]);
swap(son[l][0],son[l][1]);
swap(son[r][0],son[r][1]);
}
}
inline int node(register int x)
{
int cur;
if(q.empty()) cur=++ncnt;
else cur=q.front(),q.pop();
son[cur][0]=son[cur][1]=fa[cur]=0;
val[cur]=sum[cur]=gss[cur]=x;
lx[cur]=rx[cur]=max(0,x);
sam[cur]=rev[cur]=0;
siz[cur]=1;
return cur;
}
inline int kth(register int x)
{
int t=root;
while(1)
{
pushdown(t);
if(son[t][0]&&x<=siz[son[t][0]])
t=son[t][0];
else if(x>siz[son[t][0]]+1)
{
x-=siz[son[t][0]]+1;
t=son[t][1];
}
else
return t;
}
}
void rotate(register int p)
{
int fp=fa[p],ffp=fa[fp],way=dir(p);
son[fp][way]=son[p][way^1];
fa[son[p][way^1]]=fp;
son[ffp][dir(fp)]=p;
fa[p]=ffp;
son[p][way^1]=fp;
fa[fp]=p;
upd(fp),upd(p);
}
void splay(register int p,register int g)
{
while(fa[p]!=g)
{
int fp=fa[p],ffp=fa[fp];
if(ffp!=g)
{
if(dir(fp)==dir(p)) rotate(fp);
else rotate(p);
}
rotate(p);
}
if(!g) root=p;
}
inline void insert(register int x,register int y)
{
int u=kth(x+1),v=kth(x+2);
splay(u,0),splay(v,u);
son[v][0]=y,fa[y]=v;
upd(v),upd(u);
}
inline void recycle(register int x)
{
if(son[x][0]) recycle(son[x][0]);
if(son[x][1]) recycle(son[x][1]);
q.push(x);
}
inline void remove(register int x,register int y)
{
int u=kth(x),v=kth(x+y+1);
splay(u,0),splay(v,u);
recycle(son[v][0]);
son[v][0]=0;
upd(v),upd(u);
}
inline int qsum(register int x,register int y)
{
int u=kth(x),v=kth(x+y+1);
splay(u,0),splay(v,u);
return sum[son[v][0]];
}
int build(register int l,register int r,int *qaq)
{
if(l>r) return 0;
int mid=(l+r)>>1,cur=node(qaq[mid]);
if(l==r) return cur;
if((son[cur][0]=build(l,mid-1,qaq))) fa[son[cur][0]]=cur;
if((son[cur][1]=build(mid+1,r,qaq)))fa[son[cur][1]]=cur;
upd(cur);
return cur;
}
inline void update(register int x,register int y,register int z)
{
int u=kth(x),v=kth(x+y+1);
splay(u,0),splay(v,u);
int w=son[v][0];
sam[w]=1,val[w]=z,sum[w]=siz[w]*z;
lx[w]=rx[w]=max(sum[w],0);
if(z<0) gss[w]=z;
else gss[w]=sum[w];
upd(v),upd(u);
}
inline void reverse(register int x,register int y)
{
int u=kth(x),v=kth(x+y+1);
splay(u,0),splay(v,u);
int w=son[v][0];
if(!sam[w])
{
rev[w]^=1;
swap(son[w][0],son[w][1]);
swap(lx[w],rx[w]);
upd(v),upd(u);
}
}
int main()
{
n=read();
m=read();
for(register int i=2;i<=n+1;++i)
a[i]=read();
gss[0]=val[0]=-inf;
a[1]=a[n+2]=-inf;
n+=2;
build(1,n,a);
root=1;
int pos,num,tot;
for(register int i=1;i<=m;++i)
{
scanf("%s",opt);
if(opt[0]=='I')
{
pos=read(),num=read();
memset(a,0,sizeof a);
for(register int j=1;j<=num;++j)
a[j]=read();
insert(pos,build(1,num,a));
}
else if(opt[0]=='D')
{
pos=read(),num=read();
remove(pos,num);
}
else if(opt[0]=='M'&&opt[3]=='E')
{
pos=read(),num=read(),tot=read();
update(pos,num,tot);
}
else if(opt[0]=='R')
{
pos=read(),num=read();
reverse(pos,num);
}
else if(opt[0]=='G')
{
pos=read(),num=read();
printf("%d\n",qsum(pos,num));
}
else if(opt[0]=='M'&&opt[1]=='A'&&opt[2]=='X')
printf("%d\n",gss[root]);
}
return 0;
}
洛谷 P2042 【[NOI2005]维护数列】的更多相关文章
- 洛谷 P2042 [NOI2005]维护数列-Splay(插入 删除 修改 翻转 求和 最大的子序列)
因为要讲座,随便写一下,等讲完有时间好好写一篇splay的博客. 先直接上题目然后贴代码,具体讲解都写代码里了. 参考的博客等的链接都贴代码里了,有空再好好写. P2042 [NOI2005]维护数列 ...
- 洛谷P2042 [NOI2005]维护数列
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #in ...
- 洛谷.2042.[NOI2005]维护数列(Splay)
题目链接 2017.12.24 第一次写: 时间: 2316ms (1268ms) 空间: 19.42MB (19.5MB)(O2) 注:洛谷测的时间浮动比较大 /* 插入一段数:将这些数先单独建一棵 ...
- 【洛谷P2042】维护数列
题目大意:维护一个序列,支持区间插入,区间删除,区间翻转,查询区间元素和,查询区间最大子段和操作. 题解:毒瘤题...QAQ打完这道题发现自己以前学了一个假的 Splay.. 对于区间操作,用 spl ...
- P2042 [NOI2005]维护数列 && Splay区间操作(四)
到这里 \(A\) 了这题, \(Splay\) 就能算入好门了吧. 今天是个特殊的日子, \(NOI\) 出成绩, 大佬 \(Cu\) 不敢相信这一切这么快, 一下子机房就只剩我和 \(zrs\) ...
- P2042 [NOI2005]维护数列[splay或非旋treap·毒瘤题]
P2042 [NOI2005]维护数列 数列区间和,最大子列和(必须不为空),支持翻转.修改值.插入删除. 练码力的题,很毒瘤.个人因为太菜了,对splay极其生疏,犯了大量错误,在此记录,望以后一定 ...
- Luogu P2042 [NOI2005]维护数列(平衡树)
P2042 [NOI2005]维护数列 题意 题目描述 请写一个程序,要求维护一个数列,支持以下\(6\)种操作:(请注意,格式栏中的下划线'_'表示实际输入文件中的空格) 输入输出格式 输入格式: ...
- BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay)
手动博客搬家: 本文发表于20180825 00:34:49, 原地址https://blog.csdn.net/suncongbo/article/details/82027387 题目链接: (l ...
- Luogu P2042 [NOI2005]维护数列
题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线' _ '表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...
- P2042 [NOI2005]维护数列
思路 超级恶心的pushdown 昏天黑地的调 让我想起了我那前几个月的线段树2 错误 这恶心的一道题终于过了 太多错误,简直说不过来 pushup pushdown 主要就是这俩不太清晰,乱push ...
随机推荐
- JVM内存管理 《深入分析java web 技术内幕》第八章
8.1 物理内存与虚拟内存 物理内存RAM(随机存储器),寄存单元为寄存器,用于存储计算单元执行指令的中间结果. 连接处理器和RAM或者处理器和寄存器的是地址总线,这个地址的宽度影响了物理地址的索引范 ...
- Linux 通过编译安装apache服务以及配置
Linux 编译安装apache服务 一.安装 1.通过编译安装,首先需要下载源代码安装包 apache下载链接:http://httpd.apache.org/download.cgi 2.解开源代 ...
- PHP程序污点型漏洞静态检测方法
这篇文献,作者针对基于PHP语言开发的web应用程序产生的污点型漏洞,提出了一种静态代码分析检测的方法. 先解释一下什么叫污点型漏洞,由于对于用户的输入没有进行有效的过滤,使其进入敏感函数 ...
- 记录Nginx模块开发
--with-http_stub_status_module模块:Nginx的客户端状态 Syntax:stub_status Default:-- Content:server,location l ...
- Linux Collection:系统信息和配置
PAS Linux系统配置相关文件 /etc 目录中是系统和各类软件的配置文件 /var/log 系统日志 /proc 系统运行信息 PAS /boot空间不足 查看内核 dpkg --get-sel ...
- 用 PLSQL 创建新用户及导入 dmp
一.创建表空间 在导入 dmp 文件之前,你要在数据库里面给它分配一片存储它的地方(表空间). 如果我们知道需要导入的数据库的表空间直接创建就可以,如果不不知道,也没有关系,我们可以用 txt 打开 ...
- 【Teradata UDF】中文按字符查找chs_instr
一.场景描述 数据库为ASCII编码单字节存储,在查询中文时可能会出现错误结果.例如查询like“房”字,会查询出不含“房”,含“朔科”的结果. select * from Tablename01 w ...
- ValueOf()和toString()
var colors = ["red", "blue", "green"]; // 创建一个包含3 个字符串的数组 console.log( ...
- Vue项目分环境打包的实现步骤
转:https://blog.csdn.net/xinzi11243094/article/details/80521878 方法一:亲测真的有效 在项目开发中,我们的项目一般分为开发版.测试版.Pr ...
- C#深度学习の接口传参(interface)-----接口的妙用
一.接口可以干嘛 我们知道,接口的本质是一个约束规范,委托是方法纵向(形式上)的封装,接口是不同方法横向(广度)的封装 接口中不能有变量,但是可以有属性方法.常见的,我们可以用接口: 1.实现需求方的 ...