P2042 [NOI2005] 维护数列
请写一个程序,要求维护一个数列,支持以下 \(6\) 种操作:
编号 | 名称 | 格式 | 说明 |
---|---|---|---|
1 | 插入 | \(\operatorname{INSERT}\ posi \ tot \ c_1 \ c_2 \cdots c_{tot}\) | 在当前数列的第 \(posi\) 个数字后插入 \(tot\) 个数字:\(c_1, c_2 \cdots c_{tot}\);若在数列首插入,则 \(posi\) 为 \(0\) |
2 | 删除 | \(\operatorname{DELETE} \ posi \ tot\) | 从当前数列的第 \(posi\) 个数字开始连续删除 \(tot\) 个数字 |
3 | 修改 | \(\operatorname{MAKE-SAME} \ posi \ tot \ c\) | 从当前数列的第 \(posi\) 个数字开始的连续 \(tot\) 个数字统一修改为 \(c\) |
4 | 翻转 | \(\operatorname{REVERSE} \ posi \ tot\) | 取出从当前数列的第 \(posi\) 个数字开始的 \(tot\) 个数字,翻转后放入原来的位置 |
5 | 求和 | \(\operatorname{GET-SUM} \ posi \ tot\) | 计算从当前数列的第 \(posi\) 个数字开始的 \(tot\) 个数字的和并输出 |
6 | 求最大子列和 | \(\operatorname{MAX-SUM}\) | 求出当前数列中和最大的一段子列,并输出最大和 |
数据规模与约定
- 对于 \(100\%\) 的数据,任何时刻数列中最多含有 \(5 \times 10^5\) 个数,任何时刻数列中任何一个数字均在 \([-10^3, 10^3]\) 内,\(1 \le M \le 2 \times 10^4\),插入的数字总数不超过 \(4 \times 10^6\)。
Solution:
如果没有最大子段和的话那么这题就是一个普通的平衡树板子,但是有了这个诡异的最大字段和我们就需要在pushup的时候尤为小心
这就是你一道紫题写一个早上的理由?(╯°Д°)╯︵ ┻━┻
由于这题我们要用平衡树维护最大子段和,所以我们需要在 pushup 时加上当前节点的贡献 \(t[x].val\) 同时,如果想写得省事一点,\(lmx,rmx\) 就不能定义为强制取左/右端点时的区间最大,而是不强制取左/右端点的区间最大。其最小值为 \(0\) (可以不取)。只有区间最大字段和 \(mx\) 需要强制取。
然后这题按题意维护平衡树即可。
还有就是这题虽然最多只有 \(5*10^5\) 个数同时在线,但是历史可能有 \(4*10^6\) 个数,所以我们需要将那些被用过的闲置空间放到 【数据删除】 上回收一下
然后这题就愉快(存疑)的做完了
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;
}