955. 维护数列
题目链接
955. 维护数列
请写一个程序,要求维护一个数列,支持以下 \(6\) 种操作:(请注意,格式栏 中的下划线 _
表示实际输入文件中的空格)
输入格式
第 \(1\) 行包含两个数 \(N\) 和 \(M\),\(N\) 表示初始时数列中数的个数,\(M\) 表示要进行的操作数目。
第 \(2\) 行包含 \(N\) 个数字,描述初始时的数列。
以下 \(M\) 行,每行一条命令,格式参见问题描述中的表格。
输出格式
对于输入数据中的 GET-SUM
和 MAX-SUM
操作,向输出文件依次打印结果,每个答案(数字)占一行。
数据范围与约定
你可以认为在任何时刻,数列中至少有 \(1\) 个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
\(50\%\) 的数据中,任何时刻数列中最多含有 \(30000\) 个数;\(100\%\) 的数据中,任何时刻数列中最多含有 \(500000\) 个数。
\(100\%\) 的数据中,任何时刻数列中任何一个数字均在 \([-1000, 1000]\) 内。
\(100\%\) 的数据中,\(M \le 20000\),插入的数字总数不超过 \(4000000\) 个,输入文件大小不超过 \(20\ MBytes\)。
输入样例:
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
输出样例:
-1
10
1
10
解题思路
splay,动态开点,内存回收机制
开两个懒标记:\(same,rev\),表示修改和翻转标记,这两个标记其一的改变不会造成另一个的变化,可用常见数据结构维护,而操作涉及 \(插入\) 和 \(删除\) 操作,线段树不好维护,而 \(splay\) 很好操作,即将对应区间操作转化为某一棵子树的操作,而由于插入的数据很大,为了避免超内存,可引入内存回收机制,即进行删除操作时可以将删除的节点编号回收。其他操作同线段树
- 时间复杂度:\(O((n+m)\times logn)\)
代码
// Problem: 维护数列
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/957/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=5e5+5,inf=1e9;
int n,m,a[N],save[N],cnt,root;
struct Tr
{
int s[2],p,v,sz,lmx,rmx,mx,sum,same,rev;
void init(int _p,int _v)
{
p=_p;
v=mx=sum=_v;
s[0]=s[1]=same=rev=0;
lmx=rmx=max(0,v);
sz=1;
}
}tr[N];
void pushup(int u)
{
auto &p=tr[u],&l=tr[p.s[0]],&r=tr[p.s[1]];
p.sz=l.sz+r.sz+1;
p.sum=l.sum+r.sum+p.v;
p.lmx=max(l.lmx,l.sum+p.v+r.lmx);
p.rmx=max(r.rmx,r.sum+p.v+l.rmx);
p.mx=max({l.mx,r.mx,l.rmx+p.v+r.lmx});
}
void pushdown(int u)
{
auto &p=tr[u],&l=tr[tr[u].s[0]],&r=tr[tr[u].s[1]];
if(p.rev)
{
swap(l.s[0],l.s[1]),swap(l.lmx,l.rmx);
swap(r.s[0],r.s[1]),swap(r.lmx,r.rmx);
p.rev=0,l.rev^=1,r.rev^=1;
}
if(p.same)
{
l.same=1,l.v=p.v,l.sum=l.sz*p.v;
r.same=1,r.v=p.v,r.sum=r.sz*p.v;
if(p.v>0)
{
l.lmx=l.rmx=l.mx=l.sum;
r.lmx=r.rmx=r.mx=r.sum;
}
else
{
l.mx=p.v,l.lmx=l.rmx=0;
r.mx=p.v,r.lmx=r.rmx=0;
}
tr[u].same=0;
}
}
int build(int l,int r,int p)
{
int u=save[cnt--];
int mid=l+r>>1;
tr[u].init(p,a[mid]);
if(l<mid)tr[u].s[0]=build(l,mid-1,u);
if(r>mid)tr[u].s[1]=build(mid+1,r,u);
pushup(u);
return u;
}
void rotate(int x)
{
int y=tr[x].p,z=tr[y].p;
int k=tr[y].s[1]==x;
tr[z].s[tr[z].s[1]==y]=x,tr[x].p=z;
tr[y].s[k]=tr[x].s[k^1],tr[tr[x].s[k^1]].p=y;
tr[x].s[k^1]=y,tr[y].p=x;
pushup(y),pushup(x);
}
void splay(int x,int k)
{
while(tr[x].p!=k)
{
int y=tr[x].p,z=tr[y].p;
if(z!=k)
{
if((tr[z].s[1]==y)^(tr[y].s[1]==x))rotate(x);
else
rotate(y);
}
rotate(x);
}
if(!k)root=x;
}
int get_k(int k)
{
int u=root;
while(u)
{
pushdown(u);
if(tr[tr[u].s[0]].sz>=k)u=tr[u].s[0];
else if(tr[tr[u].s[0]].sz+1==k)return u;
else
k-=tr[tr[u].s[0]].sz+1,u=tr[u].s[1];
}
return -1;
}
void dfs(int u)
{
if(tr[u].s[0])dfs(tr[u].s[0]);
if(tr[u].s[1])dfs(tr[u].s[1]);
save[++cnt]=u;
}
int main()
{
for(int i=1;i<N;i++)save[++cnt]=i;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
a[0]=a[n+1]=-inf;
root=build(0,n+1,0);
while(m--)
{
char op[10];
int pos,k,c;
scanf("%s",op);
if(!strcmp(op,"INSERT"))
{
scanf("%d%d",&pos,&k);
for(int i=0;i<k;i++)scanf("%d",&a[i]);
int l=get_k(pos+1),r=get_k(pos+2);
splay(l,0),splay(r,l);
tr[r].s[0]=build(0,k-1,r);
pushup(r),pushup(l);
}
else if(!strcmp(op,"DELETE"))
{
scanf("%d%d",&pos,&k);
int l=get_k(pos),r=get_k(pos+k+1);
splay(l,0),splay(r,l);
dfs(tr[r].s[0]),tr[r].s[0]=0;
pushup(r),pushup(l);
}
else if(!strcmp(op,"MAKE-SAME"))
{
scanf("%d%d%d",&pos,&k,&c);
int l=get_k(pos),r=get_k(pos+k+1);
splay(l,0),splay(r,l);
auto &p=tr[r].s[0];
tr[p].v=c;
tr[p].same=1;
tr[p].sum=tr[p].sz*c;
if(c>0)tr[p].lmx=tr[p].rmx=tr[p].mx=tr[p].sum;
else
tr[p].lmx=tr[p].rmx=0,tr[p].mx=c;
pushup(r),pushup(l);
}
else if(!strcmp(op,"REVERSE"))
{
scanf("%d%d",&pos,&k);
int l=get_k(pos),r=get_k(pos+k+1);
splay(l,0),splay(r,l);
auto &p=tr[r].s[0];
tr[p].rev^=1;
swap(tr[p].lmx,tr[p].rmx);
swap(tr[p].s[0],tr[p].s[1]);
pushup(r),pushup(l);
}
else if(!strcmp(op,"GET-SUM"))
{
scanf("%d%d",&pos,&k);
int l=get_k(pos),r=get_k(pos+k+1);
splay(l,0),splay(r,l);
printf("%d\n",tr[tr[r].s[0]].sum);
}
else
printf("%d\n",tr[root].mx);
}
return 0;
}