P2042 [NOI2005] 维护数列

P2042 [NOI2005] 维护数列

请写一个程序,要求维护一个数列,支持以下 6 种操作:

编号 名称 格式 说明
1 插入 INSERT posi tot c1 c2ctot 在当前数列的第 posi 个数字后插入 tot 个数字:c1,c2ctot;若在数列首插入,则 posi0
2 删除 DELETE posi tot 从当前数列的第 posi 个数字开始连续删除 tot 个数字
3 修改 MAKE-SAME posi tot c 从当前数列的第 posi 个数字开始的连续 tot 个数字统一修改为 c
4 翻转 REVERSE posi tot 取出从当前数列的第 posi 个数字开始的 tot 个数字,翻转后放入原来的位置
5 求和 GET-SUM posi tot 计算从当前数列的第 posi 个数字开始的 tot 个数字的和并输出
6 求最大子列和 MAX-SUM 求出当前数列中和最大的一段子列,并输出最大和

数据规模与约定

  • 对于 100% 的数据,任何时刻数列中最多含有 5×105 个数,任何时刻数列中任何一个数字均在 [103,103] 内,1M2×104,插入的数字总数不超过 4×106

Solution:

如果没有最大子段和的话那么这题就是一个普通的平衡树板子,但是有了这个诡异的最大字段和我们就需要在pushup的时候尤为小心

这就是你一道紫题写一个早上的理由?(╯°Д°)╯︵ ┻━┻

由于这题我们要用平衡树维护最大子段和,所以我们需要在 pushup 时加上当前节点的贡献 t[x].val 同时,如果想写得省事一点,lmx,rmx 就不能定义为强制取左/右端点时的区间最大,而是不强制取左/右端点的区间最大。其最小值为 0 (可以不取)。只有区间最大字段和 mx 需要强制取。

然后这题按题意维护平衡树即可。

还有就是这题虽然最多只有 5105 个数同时在线,但是历史可能有 4106 个数,所以我们需要将那些被用过的闲置空间放到 【数据删除】 上回收一下

然后这题就愉快(存疑)的做完了

Code:

#include<bits/stdc++.h>
const int N=5e5+5;
using namespace std;
inline int Max(int x,int y){return x>y ? x : y;}
int n,m,rt,cnt;
queue<int> Q;
int A[N];
//FHQ_Treap:
struct Tree{
int ls,rs,val,lmx,rmx,mx,sum,tag,rev,siz,pri;
}t[N];
inline int rd(){return rand()*rand()+17;}
inline int Node(int val){int res=Q.front();Q.pop();t[res]={0,0,val,Max(0,val),Max(0,val),val,val,N,0,1,rd()};return res;}
int flag=0;
inline void pushup(int x)
{
int ls=t[x].ls,rs=t[x].rs;
t[x].siz=t[ls].siz+t[rs].siz+1;
t[x].sum=t[ls].sum+t[rs].sum+t[x].val;
t[x].lmx=Max(Max(t[ls].lmx,t[ls].sum+t[rs].lmx+t[x].val),0);
t[x].rmx=Max(Max(t[rs].rmx,t[rs].sum+t[ls].rmx+t[x].val),0);
t[x].mx=Max(t[ls].rmx+t[rs].lmx,0)+t[x].val;
if(ls)t[x].mx=Max(t[x].mx,t[ls].mx);
if(rs)t[x].mx=Max(t[x].mx,t[rs].mx);
}
inline void rev(int x)
{
swap(t[x].lmx,t[x].rmx);
t[x].rev^=1;swap(t[x].ls,t[x].rs);
}
inline void change(int x,int tag)
{
t[x].sum=t[x].siz*tag;
t[x].lmx=t[x].rmx=max(0,t[x].sum);
t[x].mx=max(t[x].sum,tag);
t[x].val=t[x].tag=tag;
}
inline void pushdown(int x)
{
int ls=t[x].ls,rs=t[x].rs,tag=t[x].tag;
if(t[x].rev)
{
if(ls)rev(ls);
if(rs)rev(rs);
t[x].rev=0;
}
if(t[x].tag!=N)
{
if(ls)change(ls,tag);
if(rs)change(rs,tag);
t[x].tag=N;
}
return ;
}
inline void splite(int x,int &a,int &b,int k)
{
if(!x){a=b=0;return ;}
int tmp=t[t[x].ls].siz+1;
pushdown(x);
if(k>=tmp){a=x;splite(t[x].rs,t[x].rs,b,k-tmp);}
else {b=x;splite(t[x].ls,a,t[x].ls,k);}
pushup(x);
}
inline int merge(int x,int y)
{
if(!x||!y)return x|y;
pushdown(x);pushdown(y);
if(t[x].pri<t[y].pri){t[x].rs=merge(t[x].rs,y);pushup(x);return x;}
else {t[y].ls=merge(x,t[y].ls);pushup(y);return y;}
}
void insert(int pos)
{
int a,b;
splite(rt,a,b,pos);
for(int i=1;i<=A[0];i++)
{
a=merge(a,Node(A[i]));
}
rt=merge(a,b);
A[0]=0;
}
inline void recycle(int x){if(!x)return ;Q.push(x);recycle(t[x].ls);recycle(t[x].rs);}
void del(int x,int tot)
{
int a,b,c;
splite(rt,a,b,x-1);
splite(b,b,c,tot);
recycle(b);
rt=merge(a,c);
}
void same(int x,int tot,int tag)
{
int a,b,c;
splite(rt,a,b,x-1);
splite(b,b,c,tot);
change(b,tag);
rt=merge(merge(a,b),c);
}
void reverse(int x,int tot)
{
int a,b,c;
splite(rt,a,b,x-1);
splite(b,b,c,tot);
rev(b);
rt=merge(merge(a,b),c);
}
void sum(int x,int tot)
{
int a,b,c;
splite(rt,a,b,x-1);
splite(b,b,c,tot);
printf("%d\n",t[b].sum);
rt=merge(merge(a,b),c);
}
char s[N];
void work()
{
cin>>n>>m;
for(int i=N-1;i;i--)Q.push(i);
for(int i=1;i<=n;i++)
{
scanf("%d",&A[++A[0]]);
}
insert(0);
int pos,tot,tag;
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if(s[0]=='M'&&s[2]=='X')
{
printf("%d\n",t[rt].mx);continue;
}
scanf("%d%d",&pos,&tot);
if(s[0]=='I')
{
for(int i=1;i<=tot;i++)scanf("%d",&A[++A[0]]);
insert(pos);continue;
}
if(s[0]=='D')
{
del(pos,tot);
}
if(s[0]=='M')
{
scanf("%d",&tag);
same(pos,tot,tag);
}
if(s[0]=='R')
{
reverse(pos,tot);
}
if(s[0]=='G')
{
sum(pos,tot);
}
}
}
int main()
{
srand(998244353);
//freopen("P2042_2.in","r",stdin);freopen("P2042.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示