题目链接
输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。第2行包含N个数字,描述初始时的数列。以下M行,每行一条命令,格式参见问题描述中的表格。
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Splay
题解:要操作区间 [ L,R ] 。把第L-1个点伸展的根,把第R+1个点伸展到根下面,那么第R+1个点的左子树就是区间[ L , R ] 。跟线段树区间操作类似,对区间打上延时标记即可。
对于插入操作来说,先将插入序列建成一个完全二叉树,然后再插入对应位置即可
对于删除操作来说,先将对应区间伸展出来,删除即可
对于询问区间和,我们维护每个子树的和
对于询问最大连续子区间来说,我们还要维护区间的以做端点为起点的最大连续和,以右端点为起点的最大连续和,已经区间最大连续和。
详情和参加论文:运用伸展树解决数列维护问题
代码如下:
#include<stdio.h> #include<algorithm> #include<iostream> #include<string.h> #include<string> 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; }