P2042 [NOI2005]维护数列

数列区间和,最大子列和(必须不为空),支持翻转、修改值、插入删除。

练码力的题,很毒瘤。个人因为太菜了,对splay极其生疏,犯了大量错误,在此记录,望以后一定要多多回顾!!!!

(以后复习splay板子干脆就这道题算了)


1.审题问题(明明就是题目没说清楚的说) 最大子序列和不能为空,也就是必有数,有负数你也得选。

2.思路方面:

关于插入:在要插入的地方通过splay把他腾出空当不就行了。即把k旋到根,k+1旋到右儿子,则k+1左儿子必为空,此时把数列二分构建成一颗平衡的树,挂上去就行了。

关于删除:同上,把删除区间搞出来,把他咔掉。但是这题卡空间,找题目意思最多会插入4500000个数,每个点还要维护接近10个变量,肯定炸。所以要将冗余转态的节点,也就是删除的节点回收扔到队列里去,下次插入时可以在拿来用。删除时要遍历目标子树所有节点回收,但因为总共只会有4500000个数被删掉,所以累计也就几百万此操作,不影响复杂度。回收机制其实是跟别人学的,细节还见代码。

关于区间修改:打标记。不用担心边界两个点被下传到,本来操作就不会覆盖到他们。pushdown时如果有该标记优于翻转标记下传,因为其已无意义。

关于区间翻转:打标记。注意因为之前文艺平衡树那题受人误导,翻转标记也最好打上之后像线段树一样及时更新,具体原因待会讲。

关于求和:不说了吧。

关于最大子列和:这个是一个新的思路。分治。具体可以看下这题,类似的,方程看题解区,不写了。

3.错误列举

  1. 由于最大子列和不为空,所以细节有所改动。维护的区间最大前缀、后缀和还可以是0,反正他也不是答案,而且也方便更新总最大连续和。最大连续和在叶节点上就只能是该值本身,这保证不为空。既然这样,对照pushdown的细节会发现,推父亲maxsum,比较孩子大小时,孩子有时由于是空的所以相当于返回了T[0].ms,为了不干扰,必把0节点sum设成-inf。同理,边界两点也应把ms设成-inf。
  2. 毕竟码量有点大,实在很容易打错,这次出现了两个typo。copy时还当多多注意。这个我也没办法。
  3. 统一修改的标记初始值不可为0,这个想想就知道了,所以设个极小值。
  4. 翻转的标记一定要如同其他标记一样打下时立刻进行,不要等下次访问在更新信息并下传。文艺平衡树那题没问题,但这题如果打下rev标记后不及时翻转,待下次访问到时再传到儿子,由于错误的机制导致儿子不会立刻翻转。而这题由于维护最大序列和的需求,要维护左端连续和右端连续最大和,试想当我的儿子的这些信息没有被更新(翻转),我自己用了没更新前的左/右最大连续和,不是会出错?这点在这题尤其明显,我rev不及时翻转,ls和rs就不会及时更新。后果可想而知。
  5. splay记得操作后经常pushup两次
 #include<bits/stdc++.h>
#define dbg(x) cerr << #x << " = " << x <<endl
using namespace std;
typedef long long ll;
template<typename T>inline T _min(T A,T B){return A>B?B:A;}
template<typename T>inline T _max(T A,T B){return A<B?B:A;}
template<typename T>inline T _max(T A,T B,T C){return _max(_max(A,B),C);}
template<typename T>inline void _swap(T&a,T&b){a^=b^=a^=b;}
template<typename T>inline int read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+c-'',c=getchar();return f?x=-x:x;
}
const int N=+,INF=5e8;
struct tree{
int ch[],f,siz,val,sam,rev,sum,ls,rs,ms;
}T[N];
queue<int> q;
int id[N],A[N];
int n,m,tot,rt,len; inline int dir(int x){return T[T[x].f].ch[]==x;}
inline void pushup(int x){//MISTAKE:the max sum can't be empty.
int l=T[x].ch[],r=T[x].ch[];
T[x].siz=T[l].siz+T[r].siz+;
T[x].sum=T[l].sum+T[r].sum+T[x].val;
T[x].ls=_max(T[l].ls,T[l].sum+T[x].val+T[r].ls);
T[x].rs=_max(T[r].rs,T[r].sum+T[x].val+T[l].rs);//MISTAKE occured when copying.
T[x].ms=_max(T[l].ms,T[r].ms,T[l].rs+T[x].val+T[r].ls);
// dbg(x),dbg(l),dbg(r),dbg(T[x].sum),dbg(T[x].siz);
}
inline void pushdown(int x){
int l=T[x].ch[],r=T[x].ch[];
if(T[x].sam^(-INF)){
T[l].val=T[r].val=T[l].sam=T[r].sam=T[x].sam;
T[l].sum=T[l].siz*T[l].sam,T[r].sum=T[r].siz*T[r].sam;
if(T[x].sam>)T[l].ls=T[l].rs=T[l].ms=T[l].sum,T[r].ls=T[r].rs=T[r].ms=T[r].sum;
else T[l].ls=T[l].rs=T[r].ls=T[r].rs=,T[l].ms=T[r].ms=T[x].sam;
T[x].sam=-INF,T[x].rev=;
}
if(T[x].rev){
T[x].rev=,T[l].rev^=,T[r].rev^=;
_swap(T[l].ch[],T[l].ch[]),_swap(T[r].ch[],T[r].ch[]);//MISTAKE:again:typo.
_swap(T[l].ls,T[l].rs),_swap(T[r].ls,T[r].rs);//!MISTAKE:when giving down'rev'tag,update children at once!
}
}
inline void Rotate(int x){
int y=T[x].f,z=T[y].f,d=dir(x);
T[y].ch[d]=T[x].ch[d^],T[T[x].ch[d^]].f=y;
T[z].ch[dir(y)]=x,T[x].f=z;
T[x].ch[d^]=y,T[y].f=x;pushup(y),pushup(x);
}
inline void Splay(int x,int to){
while(T[x].f^to){if(T[T[x].f].f^to) dir(T[x].f)^dir(x)?Rotate(x):Rotate(T[x].f);Rotate(x);}
if(!to)rt=x;
}
int Query_kth(int x,int k){
pushdown(x);
if(k<=T[T[x].ch[]].siz)return Query_kth(T[x].ch[],k);
else if(k==T[T[x].ch[]].siz+)return x;
return Query_kth(T[x].ch[],k-T[T[x].ch[]].siz-);
}
inline void Spilt(int l,int r){
l=Query_kth(rt,l),r=Query_kth(rt,r);
Splay(l,),Splay(r,l);//cerr<<"spilt:"<<endl;dbg(l),dbg(r);
}
void Build(int L,int R,int&x,int fa){
int mid=L+R>>;
x=id[mid],T[x].siz=,T[x].val=A[mid],T[x].f=fa;
T[x].sam=-INF,T[x].rev=;//MISTAKE:the lazy-tag which represents'MAKE_SAME' can't be zero at first.
if(L==R){
T[x].sum=T[x].val;T[x].ms=T[x].val;
T[x].val>?(T[x].ls=T[x].rs=T[x].val):(T[x].ls=T[x].rs=);
// dbg(x),dbg(T[x].sum),dbg(T[x].ls),dbg(T[x].rs),dbg(T[x].ms);
return;
}
if(L<mid)Build(L,mid-,T[x].ch[],x);if(mid<R)Build(mid+,R,T[x].ch[],x);pushup(x);
}
void prebuild(int L,int R,int&x,int fa){
int mid=L+R>>;x=id[mid],T[x].siz=,T[x].val=A[mid],T[x].f=fa,T[x].sam=-INF;
if(L==R){
T[x].sum=T[x].val;T[x].ms=T[x].val;if(x==||x==n+)T[x].ms=-INF;
T[x].val>?(T[x].ls=T[x].rs=T[x].val):(T[x].ls=T[x].rs=);
return;
}
if(L<mid)prebuild(L,mid-,T[x].ch[],x);if(mid<R)prebuild(mid+,R,T[x].ch[],x);pushup(x);
}
inline void Insert(int x,int cnt){
for(register int i=;i<=cnt;++i){
read(A[i]);
if(q.empty())id[i]=++tot;
else id[i]=q.front(),q.pop();
}
Spilt(x+,x+);Build(,cnt,T[T[rt].ch[]].ch[],T[rt].ch[]);
pushup(T[rt].ch[]),pushup(rt);//MISTAKE:DON'T FORGET PUSHUP!
}
inline void Erase(int&x){
if(!x)return;
Erase(T[x].ch[]),Erase(T[x].ch[]);
q.push(x);x=;
}
inline void Delete(int x,int cnt){
Spilt(x,x+cnt+);Erase(T[T[rt].ch[]].ch[]);
pushup(T[rt].ch[]),pushup(rt);
}
inline void make_same(int x,int cnt){
Spilt(x,x+cnt+);int y=T[T[rt].ch[]].ch[],c;read(c);
T[y].val=c,T[y].sam=c,T[y].sum=T[y].siz*c;
c>?(T[y].ls=T[y].rs=T[y].ms=T[y].sum):(T[y].ls=T[y].rs=,T[y].ms=c);//MISTAKE:'y',not 'x'!
pushup(T[rt].ch[]);pushup(rt);
}
inline void Reverse(int x,int cnt){
Spilt(x,x+cnt+);int y=T[T[rt].ch[]].ch[];
T[y].rev^=;_swap(T[y].ch[],T[y].ch[]),_swap(T[y].ls,T[y].rs);
}
inline void Query_sum(int x,int cnt){Spilt(x,x+cnt+);printf("%d\n",T[T[T[rt].ch[]].ch[]].sum);}
inline void Query_max_sum(){Spilt(,len+);printf("%d\n",T[T[T[rt].ch[]].ch[]].ms);}
char s[];int pos,cnt; int main(){//freopen("ttt.in","r",stdin);//freopen(".out","w",stdout);
len=read(n),read(m);
for(register int i=;i<=n;++i)read(A[i+]),id[i+]=i+;
id[]=,id[n+]=n+;tot=n+;T[].ms=-INF;//T[0].ms must be set zero!Think about the situation that a point has only one child when pushuping.
prebuild(,n+,rt,);
while(m--){
scanf("%s",s);
if(s[]=='I')read(pos),read(cnt),Insert(pos,cnt),len+=cnt;
else if(s[]=='D')read(pos),read(cnt),Delete(pos,cnt),len-=cnt;
else if(s[]=='K')read(pos),read(cnt),make_same(pos,cnt);
else if(s[]=='R')read(pos),read(cnt),Reverse(pos,cnt);
else if(s[]=='G')read(pos),read(cnt),Query_sum(pos,cnt);
else Query_max_sum();
}
return ;
}

P2042 [NOI2005]维护数列[splay或非旋treap·毒瘤题]的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. NOI2005 维护数列(splay)

    学了半天平衡树,选择了一道题来写一写,发现题目是裸的splay模板,但是还是写不好,这个的精髓之处在于在数列的某一个位置加入一个数列,类似于treap里面的merge,然后还学到了题解里面的的回收空间 ...

  7. Luogu P2042 [NOI2005]维护数列

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

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

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

  9. P2042 [NOI2005]维护数列

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

随机推荐

  1. Android 自己定义ImageView实现圆角/圆形 附加OnTouchListener具体凝视以及Button圆角

    转载请注明出处:王亟亟的大牛之路 平时要用一些非方方正正的button之类的小伙伴们是怎样实现的?RadioButton? ImageButton? 还是其它? 今天亟亟上的是ImageView来实现 ...

  2. 淘宝数据库OceanBase SQL编译器部分 源代码阅读--解析SQL语法树

    OceanBase是阿里巴巴集团自主研发的可扩展的关系型数据库,实现了跨行跨表的事务,支持数千亿条记录.数百TB数据上的SQL操作. 在阿里巴巴集团下,OceanBase数据库支持了多个重要业务的数据 ...

  3. 《UNIX环境高级编程》读书笔记 —— 文件 I/O

    打开或创建一个文件 #include <fcntl.h> int open(const char *pathname, int oflag, .../*mode_t mode*/);    ...

  4. IPv4地址(二)网络划分

    在IPv4地址(一)中提到过,IP地址可以分成两部分,前面一部分是网络号,而后面一部分是主机号. 这里网络可以通过主机数量规模不同而分为3类:大型网络.中型网络和小型网络. 不同网络的特点 大型网络— ...

  5. Codeforces 467D Fedor and Essay bfs

    题目链接: 题意: 给定n个单词. 以下有m个替换方式.左边的单词能变成右边的单词. 替换随意次后使得最后字母r个数最少,在r最少的情况下单词总长度最短 输出字母r的个数和单词长度. 思路: 我们觉得 ...

  6. 【解决】无法连接 MKS:套接字连接尝试次数太多正在放弃

    https://blog.csdn.net/wjunsing/article/details/78496224 我的电脑 -> 右键 -> 管理 -> 服务和应用程序 -> 服 ...

  7. Java正确获取客户端真实IP方法整理

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  8. EasyPlayer RTSP 安卓Android播放器显示模式设置方法

    一般对于一个播放器,应该支持如下几种显示模式: 等比例,最大化区域显示,不裁剪 等比例,最大区域显示,裁剪 拉伸显示,铺满全屏 要实现这几种显示模式,其实只要对播放控件的布局进行些许调整即可.那Eas ...

  9. sql server charindex函数和patindex函数详解(转)

    charindex和patindex函数常常用来在一段字符中搜索字符或字符串.假如被搜索的字符中包含有要搜索的字符,那么这两个函数返回一个非零的整数,这个整数是要搜索的字符在被搜索的字符中的开始位数. ...

  10. JAVA中equals()与==的区别详解

    在进行判断操作时,常常会用到==或者equals()进行等价判断,那么两者究竟有什么区别呢,下面整理一下个人理解. 简单介绍: ==是一种引用相等性比较符,判断引用到堆上同一个对象的两个引用是相等的. ...