一直在想要做这道题,但是被那个硕大的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. input输入限制,只允许输入数字和“.”,长度不得超过20

    <input style="margin-top: 10px;width: 100%;text-align:center;" id="removeArea" ...

  2. js调用浏览器打印指定div内容

    --打印按钮事件 function printForm(){    var headstr = '<html xmlns:th="http://www.thymeleaf.org&qu ...

  3. Thinkphp volist 多重循环原样输出数组key值的使用总结

    最近因为项目的缘故,要使用到volist.在这个过程中,遇到了一些小问题,主要就是volist在循环输出多重数据的时候,如何输出key.网上查阅了不少资料,很失望的是,大多资料就是粘贴复制Thinkp ...

  4. nginx内置变量总结

    nginx内置变量 2019-02-28 变量名称 变量用途 $atg_PARAMETER      客户端GET请求中   PARAMETER字段的值                        ...

  5. 英语口语练习系列-C17-Love story

    词汇学习 break [breɪk] v. 打破 broke (过去式) The glass broke. 玻璃杯碎了. My watch broke. 我的表坏了. break the law 违法 ...

  6. 报错:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop bei

    项目中遇到父组件传值 activeIndex <Tabs :tabs="tabs" :activeIndex="activeIndex" >< ...

  7. android glide图片加载框架

    项目地址: https://github.com/bumptech/glide Glide作为安卓开发常用的图片加载库,有许多实用而且强大的功能,那么,今天就来总结一番,这次把比较常见的都写出来,但并 ...

  8. Win10系统如何在防火墙里开放端口

    Win10系统如何在防火墙里开放端口(下面傻瓜式教学) 然后怎么做呢?????? 下一步.下一步.下一步.下一步.下一步.下一步.下一步.下一步.下一步.下一步......... 随便起个名字 KO

  9. 012_py之证书过期监测及域名使用的py列表的并集差集交集

    一.由于线上域名证书快要过期,需要进行监测,顾写了一个方法用于线上证书过期监测,如下: import ssl,socket,pprint def check_domain_sslexpired(dom ...

  10. 013_实践HTTP206状态:部分内容和范围请求

    HTTP 2xx范围内的状态码表明了:"客户端发送的请求已经被服务器接受并且被成功处理了".HTTP/1.1 200 OK是HTTP请求成功后的标准响应,当你在浏览器中打开www. ...