题目链接
输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。第2行包含N个数字,描述初始时的数列。以下M行,每行一条命令,格式参见问题描述中的表格。
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Splay
题解:要操作区间 [ L,R ] 。把第L-1个点伸展的根,把第R+1个点伸展到根下面,那么第R+1个点的左子树就是区间[ L , R ] 。跟线段树区间操作类似,对区间打上延时标记即可。
对于插入操作来说,先将插入序列建成一个完全二叉树,然后再插入对应位置即可
对于删除操作来说,先将对应区间伸展出来,删除即可
对于询问区间和,我们维护每个子树的和
对于询问最大连续子区间来说,我们还要维护区间的以做端点为起点的最大连续和,以右端点为起点的最大连续和,已经区间最大连续和。
详情和参加论文:运用伸展树解决数列维护问题
代码如下:
#include
#include
#include
#include
#include
typedef long long LL;
const int inf=0x3fffffff;
const int nn=210000;
using namespace std;
struct node
{
int val;
int cnt;
LL sum;
LL asum,lsum,rsum;
int xg;
bool fz;
node* pre;
node* ch[2];
}*root;
void fz(node* o)
{
swap(o->ch[0],o->ch[1]);
swap(o->lsum,o->rsum);
}
void fg(node* o,LL val)
{
o->val=val;
o->sum=val*o->cnt;
if(val>0)
o->asum=o->lsum=o->rsum=o->sum;
else
o->asum=o->lsum=o->rsum=val;
}
void push_down(node* o)
{
if(o==NULL)
return ;
if(o->xg!=inf)
{
if(o->ch[0]!=NULL)
{
o->ch[0]->xg=o->xg;
fg(o->ch[0],o->xg);
}
if(o->ch[1]!=NULL)
{
o->ch[1]->xg=o->xg;
fg(o->ch[1],o->xg);
}
o->xg=inf;
}
if(o->fz)
{
if(o->ch[0]!=NULL)
{
o->ch[0]->fz=!o->ch[0]->fz;
fz(o->ch[0]);
}
if(o->ch[1]!=NULL)
{
o->ch[1]->fz=!o->ch[1]->fz;
fz(o->ch[1]);
}
o->fz=false;
}
}
void push_up(node* o)
{
if(o==NULL)
return ;
push_down(o);
o->cnt=1;
o->sum=o->val;
if(o->ch[0]!=NULL)
{
o->cnt+=o->ch[0]->cnt;
o->sum+=o->ch[0]->sum;
}
if(o->ch[1]!=NULL)
{
o->cnt+=o->ch[1]->cnt;
o->sum+=o->ch[1]->sum;
}
if(o->ch[0]!=NULL&&o->ch[1]!=NULL)
{
o->asum=max(o->ch[0]->asum,o->ch[1]->asum);
o->asum=max(o->asum,(LL)o->val);
o->asum=max(o->asum,o->ch[0]->rsum+o->val);
o->asum=max(o->asum,o->ch[1]->lsum+o->val);
o->asum=max(o->asum,o->ch[0]->rsum+o->val+o->ch[1]->lsum);
o->lsum=max(o->ch[0]->lsum,o->ch[0]->sum+o->val);
o->lsum=max(o->lsum,o->ch[0]->sum+o->val+o->ch[1]->lsum);
o->rsum=max(o->ch[1]->rsum,o->ch[1]->sum+o->val);
o->rsum=max(o->rsum,o->ch[1]->sum+o->val+o->ch[0]->rsum);
}
else if(o->ch[0]!=NULL&&o->ch[1]==NULL)
{
o->asum=max(o->ch[0]->asum,(LL)o->val);
o->asum=max(o->asum,o->val+o->ch[0]->rsum);
o->lsum=max(o->ch[0]->lsum,o->ch[0]->sum+o->val);
o->rsum=max((LL)o->val,o->val+o->ch[0]->rsum);
}
else if(o->ch[0]==NULL&&o->ch[1]!=NULL)
{
o->asum=max(o->ch[1]->asum,(LL)o->val);
o->asum=max(o->asum,o->val+o->ch[1]->lsum);
o->lsum=max((LL)o->val,o->val+o->ch[1]->lsum);
o->rsum=max(o->ch[1]->rsum,o->val+o->ch[1]->sum);
}
else
o->asum=o->lsum=o->rsum=o->val;
}
void Rotate(node* o)
{
node* tem=o->pre;
push_down(tem);
push_down(o);
int d;
if(tem->ch[0]==o) d=0;
else d=1;
tem->ch[d]=o->ch[d^1];
if(o->ch[d^1]!=NULL)
o->ch[d^1]->pre=tem;
if(tem->pre!=NULL)
{
if(tem->pre->ch[0]==tem)
tem->pre->ch[0]=o;
else
tem->pre->ch[1]=o;
}
o->pre=tem->pre;
o->ch[d^1]=tem;
tem->pre=o;
push_up(tem);
}
void Splay(node* o,node* f)
{
node* x;
node* y;
int d1,d2;
while(o->pre!=f)
{
if(o->pre->pre==f)
Rotate(o);
else
{
x=o->pre;
y=x->pre;
if(y->ch[0]==x) d1=0;
else d1=1;
if(x->ch[0]==o) d2=0;
else d2=1;
if(d1==d2)
{
Rotate(x);
Rotate(o);
}
else
{
Rotate(o);
Rotate(o);
}
}
}
push_up(o);
if(f==NULL)
root=o;
}
node* select(node* o,int k,node* f)
{
push_down(o);
int tem=0;
if(o->ch[0]!=NULL)
{
tem+=o->ch[0]->cnt;
}
if(tem>=k)
return select(o->ch[0],k,f);
else if(tem+1==k)
{
Splay(o,f);
return o;
}
else
return select(o->ch[1],k-tem-1,f);
}
node* build(node* pre,int *a,int l,int r)
{
node* re;
re=new node;
int mid=(l+r)/2;
re->val=a[mid];
re->pre=pre;
re->fz=false;
re->xg=inf;
re->ch[0]=re->ch[1]=NULL;
if(l==r)
{
push_up(re);
return re;
}
if(l<=mid-1)
re->ch[0]=build(re,a,l,mid-1);
re->ch[1]=build(re,a,mid+1,r);
push_up(re);
return re;
}
void Clear(node* &o)
{
if(o==NULL)
return ;
Clear(o->ch[0]);
Clear(o->ch[1]);
delete o;
o=NULL;
}
void Insert(int L,int R,int *a,int l,int r)
{
node* x=select(root,L,NULL);
node* y=select(root,R,x);
push_down(y);
y->ch[0]=build(y,a,l,r);
Splay(y->ch[0],NULL);
}
void Remove(int L,int R)
{
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
Clear(y->ch[0]);
Splay(y,NULL);
}
void Change(int L,int R,int c)
{
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
y->ch[0]->xg=c;
fg(y->ch[0],c);
Splay(y->ch[0],NULL);
}
void Fanzhuan(int L,int R)
{
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
y->ch[0]->fz=!y->ch[0]->fz;
fz(y->ch[0]);
Splay(y->ch[0],NULL);
}
LL Getsum(int L,int R)
{
if(L>R)
return 0;
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
return y->ch[0]->sum;
}
LL Getsum2(int L,int R)
{
if(L>R)
return 0;
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
return y->ch[0]->asum;
}
int n,m;
int a[nn];
void init()
{
root=NULL;
root=new node;
root->fz=false;
root->xg=inf;
root->val=0;
root->cnt=2;
root->pre=NULL;
root->asum=root->sum=root->lsum=root->rsum=0;
root->ch[0]=NULL;
root->ch[1]=NULL;
root->ch[1]=new node;
root->ch[1]->val=0;
root->ch[1]->cnt=1;
root->ch[1]->asum=root->ch[1]->lsum=root->ch[1]->rsum=root->ch[1]->sum=0;
root->ch[1]->pre=root;
root->ch[1]->fz=false;
root->ch[1]->xg=inf;
root->ch[1]->ch[0]=root->ch[1]->ch[1]=NULL;
}
int main()
{
int i;
char s[10];
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
if(n>=1)
Insert(1,2,a,1,n);
int pos,tot,c;
while(m--)
{
scanf("%s",s);
if(strcmp(s,"INSERT")==0)
{
scanf("%d%d",&pos,&tot);
if(tot==0)
continue;
for(i=1;i<=tot;i++)
{
scanf("%d",&a[i]);
}
Insert(pos+1,pos+2,a,1,tot);
}
else if(strcmp(s,"DELETE")==0)
{
scanf("%d%d",&pos,&tot);
if(tot==0)
continue;
Remove(pos+1,pos+tot);
}
else if(strcmp(s,"MAKE-SAME")==0)
{
scanf("%d%d%d",&pos,&tot,&c);
if(tot==0)
continue;
Change(pos+1,pos+tot,c);
}
else if(strcmp(s,"REVERSE")==0)
{
scanf("%d%d",&pos,&tot);
if(tot==0)
continue;
Fanzhuan(pos+1,pos+tot);
}
else if(strcmp(s,"GET-SUM")==0)
{
scanf("%d%d",&pos,&tot);
printf("%lld\n",Getsum(pos+1,pos+tot));
}
else if(strcmp(s,"MAX-SUM")==0)
{
printf("%lld\n",Getsum2(2,root->cnt-1));
}
}
Clear(root);
}
return 0;
}