【洛谷P2710】数列
题目
题目链接:https://www.luogu.com.cn/problem/P2710
维护一个数列,共 \(7\) 种操作:
I. INSERT x n a1 a2 .. an
在第 \(x\) 个数后插入 \(n\) 个数分别为 \(a_1\dots a_n\)。
II. DELETE x n
删除第 \(x\) 个数开始的 \(n\) 个数。
III. REVERSE x n
翻转第 \(x\) 个数开始的 \(n\) 个数的区间。
IV. MAKE-SAME x n t
将第 \(x\) 个数开始的 \(n\) 个数统一改为 \(t\)。
V. GET-SUM x n
输出第 \(x\) 个数开始的 \(n\) 个数的和。
VI. GET x
输出第 \(x\) 个数的值。
VII. MAX-SUM x n
输出第 \(x\) 个数开始的 \(n\) 个数的最大连续子序列和。
思路
很明显可以用 Splay。然后这道毒瘤题调了我至少八九小时 /kk。
主要原因还是对 Splay 不熟。其实做这道题主要目的也是练习 Splay。
代码长度一度达到 5kb /fad。
操作一、二、三、五、六都是 Spaly 的基本操作。
对于区间推平,我们在每一个区间维护一个推平标记,下次递归到子树的时候再下传标记。
对于区间最大子段和,维护区间最大前缀和,区间最大后缀和即可。转移的时候可以通过这两项来计算出区间最大子段和。
然后就没什么好说的了。这道题主要考察的不是算法,而是心态。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=500010,Inf=1e9;
int n,m,rt,last;
char type[10];
struct Splay
{
int tot,ch[N][2],lazy[N],size[N],val[N],fa[N],sum[N],lmax[N],rmax[N],smax[N],filp[N];
Splay()
{
memset(lazy,0x3f3f3f3f,sizeof(lazy));
memset(smax,0xcf,sizeof(smax));
}
int pos(int x)
{
return ch[fa[x]][1]==x;
}
void pushup(int x)
{
int lc=ch[x][0],rc=ch[x][1];
sum[x]=sum[lc]+sum[rc]+val[x];
size[x]=size[lc]+size[rc]+1;
lmax[x]=max(lmax[lc],sum[lc]+val[x]+lmax[rc]);
rmax[x]=max(rmax[rc],sum[rc]+val[x]+rmax[lc]);
smax[x]=max(max(smax[lc],smax[rc]),rmax[lc]+val[x]+lmax[rc]);
}
void pushdown(int x)
{
int lc=ch[x][0],rc=ch[x][1];
if (lazy[x]!=0x3f3f3f3f)
{
if (lc)
{
val[lc]=lazy[lc]=lazy[x];
sum[lc]=lazy[x]*size[lc];
lmax[lc]=rmax[lc]=max(lazy[x],0)*size[lc];
smax[lc]=max(lazy[x],0)*(size[lc]-1)+lazy[x];
}
if (rc)
{
val[rc]=lazy[rc]=lazy[x];
sum[rc]=lazy[x]*size[rc];
lmax[rc]=rmax[rc]=max(lazy[x],0)*size[rc];
smax[rc]=max(lazy[x],0)*(size[rc]-1)+lazy[x];
}
lazy[x]=0x3f3f3f3f;
}
if (filp[x])
{
filp[lc]^=1; filp[rc]^=1; filp[x]=0;
swap(ch[lc][0],ch[lc][1]),swap(lmax[lc],rmax[lc]);
swap(ch[rc][0],ch[rc][1]),swap(lmax[rc],rmax[rc]);
}
}
void build()
{
tot++;
val[tot]=sum[tot]=-Inf; size[tot]=1;
lmax[tot]=rmax[tot]=0; smax[tot]=-Inf;
tot++;
val[tot]=sum[tot]=Inf; size[tot]=1;
lmax[tot]=rmax[tot]=smax[tot]=Inf;
ch[1][1]=2; fa[2]=rt=1;
pushup(2); pushup(1);
}
void rotate(int x)
{
int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
pushdown(x);
fa[x]=z; ch[z][pos(y)]=x;
fa[y]=x; ch[x][k^1]=y;
fa[c]=y; ch[y][k]=c;
pushup(y); pushup(x);
}
void splay(int x,int f=0)
{
while (fa[x]!=f)
{
int y=fa[x],z=fa[y];
if (z==f) rotate(x);
else if (pos(x)==pos(y)) rotate(y),rotate(x);
else rotate(x),rotate(x);
}
if (!f) rt=x;
}
void ins(int x,int v)
{
int p=rt,f=0,k=0;
while (p)
{
pushdown(p); f=p;
if (size[ch[p][0]]>=x) p=ch[p][0],k=0;
else x-=(size[ch[p][0]]+1),p=ch[p][1],k=1;
}
fa[++tot]=f;
val[tot]=sum[tot]=v; size[tot]=1;
lmax[tot]=rmax[tot]=max(v,0); smax[tot]=v;
if (f) ch[f][k]=tot;
else rt=tot;
pushup(tot); pushup(f);
splay(tot);
}
int find(int k)
{
int p=rt;
while (k)
{
pushdown(p);
if (k==size[ch[p][0]]+1) break;
if (k<=size[ch[p][0]]) p=ch[p][0];
else k-=(size[ch[p][0]]+1),p=ch[p][1];
}
splay(p);
return p;
}
void del(int l,int r)
{
int x=find(l-1),y=find(r+1);
splay(x); splay(y,rt);
ch[y][0]=0;
pushup(y); pushup(x);
}
void rev(int l,int r)
{
int x=find(l-1),y=find(r+1);
splay(x); splay(y,rt);
x=ch[y][0]; filp[x]^=1;
swap(ch[x][0],ch[x][1]);
swap(lmax[x],rmax[x]);
pushup(y); pushup(fa[y]);
}
void update(int l,int r,int v)
{
int x=find(l-1),y=find(r+1);
splay(x); splay(y,rt);
x=ch[y][0];
lazy[x]=val[x]=v; sum[x]=v*size[x];
lmax[x]=rmax[x]=max(v,0)*size[x];
smax[x]=max(v,0)*(size[x]-1)+v;
pushup(y); pushup(fa[y]);
}
int querysum(int l,int r)
{
int x=find(l-1),y=find(r+1);
splay(x); splay(y,rt);
return sum[ch[y][0]];
}
int querymax(int l,int r)
{
int x=find(l-1),y=find(r+1);
splay(x); splay(y,rt);
return smax[ch[y][0]];
}
}splay;
int main()
{
scanf("%d%d",&n,&m);
splay.build();
for (int i=1,x;i<=n;i++)
{
scanf("%d",&x);
splay.ins(i,x);
}
for (int i=1,x,k,t;i<=m;i++)
{
for (int i=0;i<=9;i++) type[i]=' ';
scanf("%s",type);
if (type[0]=='I')
{
scanf("%d%d",&x,&k);
for (int j=1;j<=k;j++)
{
scanf("%d",&t);
splay.ins(x+j,t);
}
}
else if (type[0]=='D')
{
scanf("%d%d",&x,&k);
splay.del(x+1,x+k);
}
else if (type[0]=='R')
{
scanf("%d%d",&x,&k);
splay.rev(x+1,x+k);
}
else if (type[0]=='M' && type[2]=='K')
{
scanf("%d%d%d",&x,&k,&t);
splay.update(x+1,x+k,t);
}
else if (type[0]=='G' && type[4]=='S')
{
scanf("%d%d",&x,&k);
printf("%d\n",last=splay.querysum(x+1,x+k));
}
else if (type[0]=='G')
{
scanf("%d",&x);
printf("%d\n",last=splay.querysum(x+1,x+1));
}
else if (type[0]=='M' && type[2]=='X')
{
scanf("%d%d",&x,&k);
printf("%d\n",last=splay.querymax(x+1,x+k));
}
}
return 0;
}