能够看到,上一篇的代码中有一段叫做find我没有提到,感觉起来也没有什么用,那么他的存在意义是什么呢?
接下来我们来填一下这个坑
回到我们的主题:NOI 2005维修数列
我们刚刚讨论了区间翻转的操作方法,接下来我们来考虑区间插入和区间删除的方法。
有了上一篇的铺垫,大家应该能看都,这两个操作方法是一致的,就是将区间前驱转到根,后继转到根的右节点。
所以当我们插入一段区间的时候,我们还是把这个区间的前驱和后继转上去,然后把这段区间插到左子树就可以了
等等,怎么插?
一个一个往上扔?
这显然是不合理的。
合理的方法是,将所有数据先建成一棵树,然后直接把这棵树挂到左子节点上即可。
可是这样时间不会爆吗?
当然不会!
为什么?
我们稍微分析一下,每次建树都是O(nlog2n)的,而插入数字总数不超过4000000,也就是说,即使我们一次性将这些数全插进去,也仅仅会有点卡常
何况正常情况下这么多东西不会一口气插进去,所以是完全不必担心时间炸掉的。
那么删除一段区间也是同理了。
再往后,就是区间赋值了。
区间赋值和区间翻转很接近,但是如果进行了区间赋值,那区间翻转就没有进行的必要了,所以操作的时候注意一下顺序就好。
然后是维护区间和和维护最大子段和
区间求和操作类似线段树,我们用一个点维护他子树的和,向上更新即可
最大子段和类似小白逛公园,由维护左联通,右联通和全区间的最优解,向上合并即可
(所以有人吐槽,说这题是1/6的线段树,1/6小白逛公园,1/6文艺平衡树,还有1/2不知道什么玩意的东西)
还需要一些细节问题:
虽然说要扔进去4000000个数,但事实上,一个序列中不过500000个数,所以SPLAY空间开到500000左右就行
可是剩下那些如果直接扔就立刻RE啦
所以我们开一个队列,把原来删除的数的编号保存起来,做一个清理垃圾的机制,这样就可以保证空间不爆炸了。
那么这样的话,每个根的编号就会有变化,所以我们要用一个映射getid,记录多余的编号
可是如果这么操作,编号是很混乱的,所以我们就需要上面提到的find函数来查到这个端点在SPLAY中真实的根。
最后是恶心的代码...
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define INF 0x3f3f3f3f
#define ls tree[rt].lson
#define rs tree[rt].rson
using namespace std;
struct SPLAY
{
int lson;
int rson;
int maxval;
int maxls;
int maxrs;
int s;
int val;
bool ctag;
bool ttag;
int fa;
int huge;
}tree[1000005];
int getid[500005];
int a[500005];
int cnt=0;
int rot;
int n,m;
char s[10];
queue <int> M;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void update(int rt)
{
tree[rt].s=tree[ls].s+tree[rs].s+tree[rt].val;
tree[rt].huge=tree[ls].huge+tree[rs].huge+1;
tree[rt].maxval=max(tree[ls].maxval,max(tree[rs].maxval,tree[ls].maxrs+tree[rs].maxls+tree[rt].val));
tree[rt].maxls=max(tree[ls].maxls,tree[ls].s+tree[rt].val+tree[rs].maxls);
tree[rt].maxrs=max(tree[rs].maxrs,tree[rs].s+tree[rt].val+tree[ls].maxrs);
}
void cleanrubbish(int rt)
{
if(ls)
{
cleanrubbish(ls);
}
if(rs)
{
cleanrubbish(rs);
}
M.push(rt);
tree[rt].ttag=tree[rt].ctag=tree[rt].fa=ls=rs=0;
}
void pushdown(int rt)
{
if(tree[rt].ctag)
{
tree[rt].ctag=tree[rt].ttag=0;
if(ls)
{
tree[ls].s=tree[rt].val*tree[ls].huge;
tree[ls].ctag=1;
tree[ls].val=tree[rt].val;
}
if(rs)
{
tree[rs].s=tree[rt].val*tree[rs].huge;
tree[rs].ctag=1;
tree[rs].val=tree[rt].val;
}
if(tree[rt].val>=0)
{
if(ls)
{
tree[ls].maxval=tree[ls].maxls=tree[ls].maxrs=tree[ls].s;
}
if(rs)
{
tree[rs].maxval=tree[rs].maxls=tree[rs].maxrs=tree[rs].s;
}
}else
{
if(ls)
{
tree[ls].maxls=tree[ls].maxrs=0;
tree[ls].maxval=tree[ls].val;
}
if(rs)
{
tree[rs].maxls=tree[rs].maxrs=0;
tree[rs].maxval=tree[rs].val;
}
}
}
if(tree[rt].ttag)
{
tree[rt].ttag=0;
tree[ls].ttag^=1;
tree[rs].ttag^=1;
swap(tree[ls].maxls,tree[ls].maxrs);
swap(tree[rs].maxls,tree[rs].maxrs);
swap(tree[ls].lson,tree[ls].rson);
swap(tree[rs].lson,tree[rs].rson);
}
}
int findf(int rt,int v)
{
pushdown(rt);
if(tree[ls].huge+1==v)
{
return rt;
}else if(tree[ls].huge>=v)
{
return findf(ls,v);
}else
{
return findf(rs,v-tree[ls].huge-1);
}
}
void rotate(int st,int &to)
{
int v1=tree[st].fa;
int v2=tree[v1].fa;
int ltyp;
if(tree[v1].rson==st)
{
ltyp=1;
}else
{
ltyp=0;
}
if(v1==to)
{
to=st;
}else
{
if(tree[v2].lson==v1)
{
tree[v2].lson=st;
}else
{
tree[v2].rson=st;
}
}
if(ltyp)
{
tree[tree[st].lson].fa=v1;
tree[v1].fa=st;
tree[v1].rson=tree[st].lson;
tree[st].lson=v1;
tree[st].fa=v2;
}else
{
tree[tree[st].rson].fa=v1;
tree[v1].fa=st;
tree[v1].lson=tree[st].rson;
tree[st].rson=v1;
tree[st].fa=v2;
}
update(v1);
update(st);
}
void splay(int st,int &to)
{
while(st!=to)
{
int v1=tree[st].fa;
int v2=tree[v1].fa;
if(v1!=to)
{
if((tree[v2].lson==v1&&tree[v1].lson!=st)||(tree[v2].rson==v1&&tree[v1].rson!=st))
{
rotate(st,to);
}else
{
rotate(v1,to);
}
}
rotate(st,to);
}
}
int split(int st,int len)
{
int v1=findf(rot,st);
int v2=findf(rot,st+len+1);
splay(v1,rot);
splay(v2,tree[v1].rson);
return tree[v2].lson;
}
void reverse(int st,int len)
{
int v1=split(st,len);
if(!tree[v1].ctag)
{
tree[v1].ttag^=1;
swap(tree[v1].lson,tree[v1].rson);
swap(tree[v1].maxls,tree[v1].maxrs);
update(tree[v1].fa);
update(tree[tree[v1].fa].fa);
}
}
void buildtree(int l,int r,int f)
{
int mid=(l+r)>>1;
int v1=getid[mid];
int v2=getid[f];
if(l==r)
{
tree[v1].lson=tree[v1].rson=0;
tree[v1].maxval=tree[v1].s=tree[v1].val=a[l];
tree[v1].maxls=tree[v1].maxrs=max(tree[v1].s,0);
tree[v1].ctag=tree[v1].ttag=0;
tree[v1].huge=1;
}
if(mid>l)
{
buildtree(l,mid-1,mid);
}
if(mid<r)
{
buildtree(mid+1,r,mid);
}
tree[v1].val=a[mid];
tree[v1].fa=v2;
update(v1);
if(mid<f)
{
tree[v2].lson=v1;
}else
{
tree[v2].rson=v1;
}
}
void ins(int st,int len)
{
for(int i=1;i<=len;i++)
{
a[i]=read();
}
for(int i=1;i<=len;i++)
{
if(!M.empty())
{
getid[i]=M.front();
M.pop();
}else
{
getid[i]=++cnt;
}
}
buildtree(1,len,0);
int v=getid[(1+len)>>1];
int v1=findf(rot,st+1);
int v2=findf(rot,st+2);
splay(v1,rot);
splay(v2,tree[rot].rson);
tree[v2].lson=v;
tree[v].fa=v2;
update(v2);
update(v1);
}
void del(int st,int len)
{
int v1=split(st,len);
int f=tree[v1].fa;
tree[f].lson=0;
cleanrubbish(v1);
update(f);
update(tree[f].fa);
}
void changesame(int st,int len,int v)
{
int v1=split(st,len);
tree[v1].val=v;
tree[v1].ctag=1;
tree[v1].s=tree[v1].huge*v;
if(v>=0)
{
tree[v1].maxls=tree[v1].maxrs=tree[v1].maxval=tree[v1].s;
}else
{
tree[v1].maxls=tree[v1].maxrs=0;
tree[v1].maxval=v;
}
update(tree[v1].fa);
update(tree[tree[v1].fa].fa);
}
int query(int st,int len)
{
int v1=split(st,len);
return tree[v1].s;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("my.out","w",stdout);
n=read(),m=read();
tree[0].maxval=a[1]=a[n+2]=-INF;
for(int i=1;i<=n;i++)
{
a[i+1]=read();
getid[i]=i;
}
getid[n+1]=n+1;
getid[n+2]=n+2;
buildtree(1,n+2,0);
rot=(n+3)>>1,cnt=n+2;
while(m--)
{
scanf("%s",s);
if(s[0]=='I')
{
int st=read(),len=read();
ins(st,len);
}else if(s[0]=='D')
{
int st=read(),len=read();
del(st,len);
}else if(s[0]=='R')
{
int st=read(),len=read();
reverse(st,len);
}else if(s[0]=='G')
{
int st=read(),len=read();
printf("%d\n",query(st,len));
}else if(s[2]=='X')
{
printf("%d\n",tree[rot].maxval);
}else
{
int st=read(),len=read(),v=read();
changesame(st,len,v);
}
}
return 0;
}