一直在想要做这道题,但是被那个硕大的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]维护数列】的更多相关文章

  1. 洛谷 P2042 [NOI2005]维护数列-Splay(插入 删除 修改 翻转 求和 最大的子序列)

    因为要讲座,随便写一下,等讲完有时间好好写一篇splay的博客. 先直接上题目然后贴代码,具体讲解都写代码里了. 参考的博客等的链接都贴代码里了,有空再好好写. P2042 [NOI2005]维护数列 ...

  2. 洛谷P2042 [NOI2005]维护数列

    #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #in ...

  3. 洛谷.2042.[NOI2005]维护数列(Splay)

    题目链接 2017.12.24 第一次写: 时间: 2316ms (1268ms) 空间: 19.42MB (19.5MB)(O2) 注:洛谷测的时间浮动比较大 /* 插入一段数:将这些数先单独建一棵 ...

  4. 【洛谷P2042】维护数列

    题目大意:维护一个序列,支持区间插入,区间删除,区间翻转,查询区间元素和,查询区间最大子段和操作. 题解:毒瘤题...QAQ打完这道题发现自己以前学了一个假的 Splay.. 对于区间操作,用 spl ...

  5. P2042 [NOI2005]维护数列 && Splay区间操作(四)

    到这里 \(A\) 了这题, \(Splay\) 就能算入好门了吧. 今天是个特殊的日子, \(NOI\) 出成绩, 大佬 \(Cu\) 不敢相信这一切这么快, 一下子机房就只剩我和 \(zrs\) ...

  6. P2042 [NOI2005]维护数列[splay或非旋treap·毒瘤题]

    P2042 [NOI2005]维护数列 数列区间和,最大子列和(必须不为空),支持翻转.修改值.插入删除. 练码力的题,很毒瘤.个人因为太菜了,对splay极其生疏,犯了大量错误,在此记录,望以后一定 ...

  7. Luogu P2042 [NOI2005]维护数列(平衡树)

    P2042 [NOI2005]维护数列 题意 题目描述 请写一个程序,要求维护一个数列,支持以下\(6\)种操作:(请注意,格式栏中的下划线'_'表示实际输入文件中的空格) 输入输出格式 输入格式: ...

  8. BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay)

    手动博客搬家: 本文发表于20180825 00:34:49, 原地址https://blog.csdn.net/suncongbo/article/details/82027387 题目链接: (l ...

  9. Luogu P2042 [NOI2005]维护数列

    题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线' _ '表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...

  10. P2042 [NOI2005]维护数列

    思路 超级恶心的pushdown 昏天黑地的调 让我想起了我那前几个月的线段树2 错误 这恶心的一道题终于过了 太多错误,简直说不过来 pushup pushdown 主要就是这俩不太清晰,乱push ...

随机推荐

  1. TortoiseSVN 安装时出现 please install the universal crt

    解决步骤: 1.打开 https://www.microsoft.com/zh-cn/ 2.搜索 universal crt (hotfix kb2999226) 3.点击链接 4.选择适合自己的版本 ...

  2. QT之Http请求

    今天我们介绍一下QT的http请求,这里有post和get两种方式 一.post请求方式:参数分为网址和具体请求值两个部分,有时候还需要设置头信息,看具体情况定 void MainWindow::se ...

  3. Linux 中磁盘阵列RAID10损坏以及修复

    在Linux 中磁盘阵列RAID10配置中我们已经正确配置了RAID10 ,一般来说在RAID10中最多允许50%的磁盘损毁,当然除了,同一磁盘RAID1中的硬盘设备全部损毁. 这次我们讨论一下:假设 ...

  4. Python运算符之翩若惊鸿,婉若游龙

    python中的运算符算术运算符:主要用于两个对象算数计算(加减乘除等运算)比较运算符:用于两个对象比较(判断是否相等.大于等运算)赋值运算符:用于对象的赋值,将运算符右边的值(或计算结果)赋给运算符 ...

  5. 【原】Java学习笔记025 - 内部类

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 内部类(嵌套类): ...

  6. chome(谷歌浏览器)上传文件崩溃/上传图片崩溃/打开浏览文件未响应 解决方案

    测试解决方案:关闭搜狗输入法(我用的是搜狗输入法,若使用其他输入法,此方案也可能适用),再测试是否重现浏览器崩溃问题 可选解决方案:升级搜狗输入法(如果想 卸载输入法 也可以) 前面有段时间chome ...

  7. spark-2.4.0-hadoop2.7-简单操作

    1. 说明 本文基于:spark-2.4.0-hadoop2.7-高可用(HA)安装部署 2. 启动Spark Shell 在任意一台有spark的机器上执行 # --master spark://m ...

  8. Myeclipse、eclipse安装lombok

    Lombok简介 Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法.官方地址:https:/ ...

  9. CentOS 7 中使用NTP进行时间同步

    1. NTP时钟同步方式说明NTP在linux下有两种时钟同步方式,分别为直接同步和平滑同步: 直接同步 使用ntpdate命令进行同步,直接进行时间变更.如果服务器上存在一个12点运行的任务,当前服 ...

  10. perf + Flame Graph火焰图分析程序性能

    1.perf命令简要介绍 性能调优时,我们通常需要分析查找到程序百分比高的热点代码片段,这便需要使用 perf record 记录单个函数级别的统计信息,并使用 perf report 来显示统计结果 ...