题意:
给出一个长度为n的数列和m个操作;
对每个5,6操作输出一个答案;
被bz吃掉的数据范围:
你可以认为在任何时刻,数列中至少有1个数;
输入数据一定是正确的,即指定位置的数在数列中一定存在;
50%的数据中,任何时刻数列中最多含有30 000个数;
100%的数据中,任何时刻数列中最多含有500 000个数;
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内;
100%的数据中,M ≤20 000,插入的数字总数不超过4 000 000个。
题解:
这是一道好题(笑);
首先分析一下题目;
1,2操作涉及到区间的加入删除,显然是一个splay;
3,4操作是区间的更改,对这样的大数据范围要维护延时标记;
5,6操作是输出,没啥说的;
再看数据范围,数列长度不超过500 000,插入个数不超过4 000 000;
我个蒟蒻居然直接开大数组就搞了,并没有考虑内存回收的问题;
然后WA了半天并且并不能对拍出错;
所以数组开小为什么不是RE啊!!
我开大了5倍内存在cena上A了。。。
↑所以内存要回收↑
为了方便一点去对两边取区间,我在两端加了两个无用结点;
维护6询问就是维护左面的最大值,右面的最大值和中间的最大值,分别用lm,rm,ma表示咯;
但是因为两个无用结点,让问题变得有些复杂;
1.如果无用结点值为0,那么当整个区间都为负数时答案为0,而题目要求必须取一个最大的负数;
2.如果无用结点值为负无穷,在维护sum的时候可能会出问题,并且int内负无穷加着加着就变成正无穷了(笑);
所以我记录了一个ign的标记,赋给了两个无用结点和0结点,在求最大值的时候无视他们的值;
然后说说标记的问题;
3操作小心将区间维护为0,如果仅用判断标记是否为0就会挂在这;
4操作注意一下Pushdown的时候当前结点的左右子树已经交换了,应当交换的是子树的左右子树;
交换时直接交换左右子树的标号和lm与rm即可;
别的没什么说的了,splay实现我开了结构体,不过无所谓啦;
实际上开结构体除了回收内存直接memset方便一点以外都是比较麻烦的;
附赠对拍用数据生成器一个(下面);
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 510000
#define lson tr[tr[x].ch[0]]
#define rson tr[tr[x].ch[1]]
#define which(x) (tr[tr[x].fa].ch[1]==x)
using namespace std;
struct splay_tree
{
int val,ch[2],fa,size,sum,lm,rm,ma,cov;
bool flag1,flag2,ign;
}tr[N];
char str[100];
int root,tot,st[N],top;
void Pushup(int x)
{
tr[x].sum=lson.sum+rson.sum+tr[x].val;
tr[x].size=lson.size+rson.size+1;
tr[x].lm=max(lson.lm,lson.sum+tr[x].val+max(rson.lm,0));
tr[x].rm=max(rson.rm,tr[x].val+rson.sum+max(lson.rm,0));
tr[x].ma=max(max(lson.rm,0)+(tr[x].ign?-0x3f3f3f3f:tr[x].val)+max(rson.lm,0),max(lson.ma,rson.ma));
}
void Pushdown(int x)
{
if(tr[x].flag2)
{
if(tr[x].ch[0])
{
lson.flag2=1;
lson.val=lson.cov=tr[x].cov;
lson.sum=lson.size*tr[x].cov;
lson.lm=lson.rm=lson.ma=max(lson.cov,lson.sum);
}
if(tr[x].ch[1])
{
rson.flag2=1;
rson.val=rson.cov=tr[x].cov;
rson.sum=rson.size*tr[x].cov;
rson.lm=rson.rm=rson.ma=max(rson.cov,rson.sum);
}
}
else if(tr[x].flag1)
{
lson.flag1^=1,rson.flag1^=1;
swap(lson.ch[0],lson.ch[1]);
swap(lson.lm,lson.rm);
swap(rson.ch[0],rson.ch[1]);
swap(rson.lm,rson.rm);
}
tr[x].flag1=tr[x].flag2=tr[x].cov=0;
}
int Build(int l,int r,int f)
{
if(l>r) return 0;
int mid=(l+r)>>1,x;
if(top)
x=st[top--];
else
x=++tot;
tr[x].fa=f;
tr[x].ch[0]=Build(l,mid-1,x);
scanf("%d",&tr[x].val);
tr[x].ch[1]=Build(mid+1,r,x);
if(l==r)
{
tr[x].size=1;
tr[x].sum=tr[x].val;
tr[x].lm=tr[x].rm=tr[x].ma=tr[x].val;
}
else
Pushup(x);
return x;
}
void Rotate(int x)
{
int f=tr[x].fa;
bool k=which(x);
tr[f].ch[k]=tr[x].ch[!k];
tr[tr[x].ch[!k]].fa=f;
tr[x].ch[!k]=f;
tr[tr[f].fa].ch[which(f)]=x;
tr[x].fa=tr[f].fa;
tr[f].fa=x;
Pushup(f);
Pushup(x);
}
void Splay(int x,int g)
{
if(!x) return ;
while(tr[x].fa!=g)
{
int f=tr[x].fa;
if(tr[f].fa==g)
{
Rotate(x);
continue;
}
if(which(f)^which(x))
Rotate(x);
else
Rotate(f);
Rotate(x);
}
if(!g) root=x;
}
int Rank(int x,int k)
{
if(x==0||k==0) return 0;
Pushdown(x);
if(k<=lson.size)
return Rank(tr[x].ch[0],k);
else if(k==lson.size+1)
return x;
else
return Rank(tr[x].ch[1],k-lson.size-1);
}
void Init(int n)
{
int x;
x=Rank(root,1);
Splay(x,0);
tr[x].ch[0]=++tot;
tr[tot].ign=tr[tot].size=1;
tr[tot].fa=x;
tr[tot].lm=tr[tot].rm=tr[tot].ma=-0x3f3f3f3f;
Pushup(x);
x=Rank(root,1+n);
Splay(x,0);
tr[x].ch[1]=++tot;
tr[tot].ign=tr[tot].size=1;
tr[tot].fa=x;
tr[tot].lm=tr[tot].rm=tr[tot].ma=-0x3f3f3f3f;
Pushup(x);
}
void Getback(int x)
{
if(!x) return ;
st[++top]=x;
Getback(tr[x].ch[0]);
Getback(tr[x].ch[1]);
memset(&tr[x],0,sizeof(splay_tree));
}
void Insert()
{
int p,n,x,y;
scanf("%d%d",&p,&n);
p++;
x=Rank(root,p);
Splay(x,0);
y=Rank(root,p+1);
Splay(y,x);
tr[y].ch[0]=Build(1,n,y);
Pushup(y);
Pushup(x);
}
void Delete()
{
int p,n,x,y;
scanf("%d%d",&p,&n);
p++;
x=Rank(root,p-1);
Splay(x,0);
y=Rank(root,p+n);
Splay(y,x);
Getback(tr[y].ch[0]);
tr[y].ch[0]=0;
Pushup(y);
Pushup(x);
}
void Update()
{
int p,n,v,x,y,t;
scanf("%d%d%d",&p,&n,&v);
p++;
x=Rank(root,p-1);
Splay(x,0);
y=Rank(root,p+n);
Splay(y,x);
t=tr[y].ch[0];
tr[t].flag2=1;
tr[t].val=tr[t].cov=v;
tr[t].sum=tr[t].size*v;
tr[t].lm=tr[t].rm=tr[t].ma=max(v,tr[t].sum);
Pushup(y);
Pushup(x);
}
void Reverse()
{
int p,n,x,y,t;
scanf("%d%d",&p,&n);
p++;
x=Rank(root,p-1);
Splay(x,0);
y=Rank(root,p+n);
Splay(y,x);
t=tr[y].ch[0];
tr[t].flag1^=1;
swap(tr[t].ch[0],tr[t].ch[1]);
swap(tr[t].lm,tr[t].rm);
Pushup(y);
Pushup(x);
}
void Getsum()
{
int p,n,x,y,t;
scanf("%d%d",&p,&n);
p++;
x=Rank(root,p-1);
Splay(x,0);
y=Rank(root,p+n);
Splay(y,x);
t=tr[y].ch[0];
printf("%d\n",tr[t].sum);
Pushup(y);
Pushup(x);
}
void Getmax()
{
printf("%d\n",tr[root].ma);
}
int main()
{
int n,m,i,j,k,x,y;
scanf("%d%d",&n,&m);
tr[0].ign=1;
tr[0].lm=tr[0].rm=tr[0].ma=-0x3f3f3f3f;
root=Build(1,n,0);
Init(n);
for(i=1;i<=m;i++)
{
scanf("%s",str);
switch(str[2])
{
case 'S':Insert(); break;
case 'L':Delete(); break;
case 'K':Update(); break;
case 'V':Reverse(); break;
case 'T':Getsum(); break;
case 'X':Getmax();
}
}
return 0;
}
数据生成器:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define Random rand()%2000-1000
using namespace std;
typedef long long ll;
int main()
{
srand(time(NULL));
int n=300,m=10;
int i,j,k,x,y;
printf("%d %d\n",n,m);
for(i=1;i<=n;i++)
printf("%d ",Random);
puts("");
for(i=1;i<=m;i++)
{
k=rand()%6;
if(!n) return 0;
x=rand()%n+1;
y=rand()%(n-x+1)+1;
switch(k)
{
case 0: puts("INSERT"); printf("%d %d ",x,y);
for(j=1;j<=y;j++)
printf("%d ",Random);
puts("");
n+=y;
break;
case 1: puts("DELETE");
printf("%d %d\n",x,y);
n-=y;
break;
case 2: puts("MAKE-SAME"); printf("%d %d %d\n",x,y,Random);
break;
case 3: puts("REVERSE"); printf("%d %d\n",x,y);
break;
case 4: puts("GET-SUM"); printf("%d %d\n",x,y);
break;
case 5: puts("MAX-SUM");
break;
}
}
return 0;
}