题目地址:P2042 [NOI2005]维护数列
题目大意: 给你一个数列,要求支持以下操作
编号 | 名称 | 格式 | 说明 |
---|---|---|---|
1 | 插入 | I N S E R T INSERT INSERT p o s i posi posi t o t tot tot c 1 c 2 . . . c t o t c_1c_2...c_{tot} c1c2...ctot | 在当前数列的第 p o s i posi posi 个数字后插入 t o t tot tot 个数字: c 1 c 2 . . . c t o t c_1c_2...c_{tot} c1c2...ctot $若在数列首插入,则 p o s i p o s posipos posiposi 为 0 0 0 |
2 | 删除 | D E L E T E DELETE DELETE p o s i posi posi t o t tot tot | 从当前数列的第 p o s i posi posi个数字开始连续删除 t o t tot tot个数字 |
3 | 修改 | M A K E − S A M E MAKE-SAME MAKE−SAME p o s i posi posi t o t tot tot c c c | 从当前数列的第 p o s i posi posi个数字开始的连续 t o t tot tot个数字统一修改为 c c c |
4 | 翻转 | R E V E R S E REVERSE REVERSE p o s i posi posi t o t tot tot | 取出从当前数列的第 p o s i posi posi 个数字开始的 t o t tot tot个数字,翻转后放入原来的位置 |
5 | 求和 | G E T − S U M GET-SUM GET−SUM p o s i posi posi t o t tot tot | 计算从当前数列的第 p o s i posi posi个数字开始的 t o t tot tot个数字的和并输出 |
6 | 求最大子列和 | M A X − S U M MAX-SUM MAX−SUM | 求出当前数列中和最大的一段子列,并输出最大和 |
题目分析:
看到操作时对序列的操作,首先想到splay维护,但是看看操作,实在是。。。
所以我用fhqtreap来维护的,代码少了不少,注意题目中说数列最多只有
5
e
5
5e5
5e5但插入的数字量可以达到
4
e
6
4e6
4e6,所以我们可以开一个栈,把删除的元素保存起来下次再用。
还有就是注意在维护最大子段和的时候,由于一个节点的左右儿子是他的左边和右边的序列,因此不要忘记把自己加进去 (应该没有人像我这么蠢) ,其他部分就是fhqTreap的板子,代码里有注释。
题目代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<time.h>
#define mxn 500000
using namespace std;
struct Node{
int lson,rson;
int val,size,pri;
int sum,maxn,maxnl,maxnr,cov;
bool is_rev,is_cov;
}T[mxn];
int stk[mxn+5],arr[mxn+5],rt,pos,tot,c,sz,Top=mxn;
char opt[10];
int new_node(int v){
sz=stk[Top--];
T[sz].lson=T[sz].rson=T[sz].is_cov=T[sz].is_rev=0;
T[sz].size=1;
T[sz].val=T[sz].sum=T[sz].maxn=v;
T[sz].maxnl=T[sz].maxnr=max(0,v);
T[sz].pri=rand();
return sz;
}
void del(int x){
if(!x)return;
stk[++Top]=x;
if(T[x].lson)del(T[x].lson);
if(T[x].rson)del(T[x].rson);
return;
}
void pushup(int x){
if(!x)return;
T[x].size=T[T[x].lson].size+T[T[x].rson].size+1;
T[x].sum=T[T[x].lson].sum+T[T[x].rson].sum+T[x].val;
T[x].maxn=max(T[x].val,T[T[x].lson].maxnr+T[x].val+T[T[x].rson].maxnl);
if(T[x].lson)T[x].maxn=max(T[x].maxn,T[T[x].lson].maxn);
if(T[x].rson)T[x].maxn=max(T[x].maxn,T[T[x].rson].maxn);
//maxn可能会取到负值,所以这里要判一下左右儿子是否存在
//而下面的前驱后继取不到负值,所以不用判
T[x].maxnl=max(max(T[T[x].lson].maxnl,T[T[x].lson].sum+T[x].val+T[T[x].rson].maxnl),0);
T[x].maxnr=max(max(T[T[x].rson].maxnr,T[T[x].rson].sum+T[x].val+T[T[x].lson].maxnr),0);
}
void reverse(int k){
if(!k)return;
swap(T[k].lson,T[k].rson);
swap(T[k].maxnl,T[k].maxnr);
T[k].is_rev^=1;
}
void cover(int k,int np){
if(!k)return;
T[k].val=T[k].cov=np;
T[k].sum=T[k].size*np;
T[k].maxn=max(T[k].sum,T[k].val);
T[k].maxnl=max(0,max(T[k].sum,T[k].val));
T[k].maxnr=max(0,max(T[k].sum,T[k].val));
T[k].is_cov=1;
}
void pushdown(int k){
if(!k)return;
if(T[k].is_rev){
reverse(T[k].lson);
reverse(T[k].rson);
T[k].is_rev=0;
}
if(T[k].is_cov){
cover(T[k].lson,T[k].cov);
cover(T[k].rson,T[k].cov);
T[k].is_cov=0;
}
}
void split(int now,int k,int &x,int &y){//split时树的左子树的size==k
if(!now){x=y=0;return;}
else{
pushdown(now);
if(k<=T[T[now].lson].size)
y=now,split(T[now].lson,k,x,T[now].lson);
else x=now,split(T[now].rson,k-T[T[now].lson].size-1,T[now].rson,y);
pushup(now);
}
}
int merge(int x,int y){//x<y
if(!x||!y)return x+y;
if(T[x].pri<T[y].pri){
pushdown(x);
T[x].rson=merge(T[x].rson,y);
pushup(x);
return x;
}
else{
pushdown(y);
T[y].lson=merge(x,T[y].lson);
pushup(y);
return y;
}
}
int build(int l,int r){
if(l==r)return new_node(arr[l]);
int mid=(l+r)>>1;
int x=merge(build(l,mid),build(mid+1,r));
return x;
}
int main()
{
srand(time(0));
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=mxn;i++)stk[mxn-i+1]=i;
for(int i=1;i<=n;i++)
scanf("%d",&arr[i]);
rt=merge(rt,build(1,n));
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%s",opt);
if(opt[0]=='I'){
scanf("%d %d",&pos,&tot);
for(int i=1;i<=tot;i++)
scanf("%d",&arr[i]);
split(rt,pos,x,y);
x=merge(x,build(1,tot));
rt=merge(x,y);
}
if(opt[0]=='D'){
scanf("%d %d",&pos,&tot);
split(rt,pos-1,x,y);//这个数字也要被删掉所以是pos-1
split(y,tot,y,z);
del(y);
rt=merge(x,z);
}
if(opt[0]=='M'&&opt[2]=='K'){
scanf("%d %d %d",&pos,&tot,&c);
split(rt,pos-1,x,y);
split(y,tot,y,z);
cover(y,c);
y=merge(y,z);
rt=merge(x,y);
}
if(opt[0]=='R'){
scanf("%d %d",&pos,&tot);
split(rt,pos-1,x,y);
split(y,tot,y,z);
reverse(y);
y=merge(y,z);
rt=merge(x,y);
}
if(opt[0]=='G'){
scanf("%d %d",&pos,&tot);
split(rt,pos-1,x,y);
split(y,tot,y,z);
printf("%d\n",T[y].sum);
y=merge(y,z);
rt=merge(x,y);
}
if(opt[0]=='M'&&opt[2]=='X'){
printf("%d\n",T[rt].maxn);
}
}
return 0;
}