[bzoj1500][NOI2005 维修数列] (splay区间操作)
Posted AronQi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj1500][NOI2005 维修数列] (splay区间操作)相关的知识,希望对你有一定的参考价值。
Description
Input
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Output
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Sample Input
9 8 2 -6 3 5 1 -5 -3 6 3 GET-SUM 5 4 MAX-SUM INSERT 8 3 -5 7 2 DELETE 12 1 MAKE-SAME 3 3 2 REVERSE 3 6 GET-SUM 5 4 MAX-SUM
Sample Output
-1 10 1 10
HINT
Solution
#include<cstdio> #include<iostream> #define N 500010 #define inf 0x3f3f3f3f #define mid ((x>>1)+(y>>1)+(x&y&1)) using namespace std; inline int Rin(){ int x=0,c=getchar(),f=1; for(;c<48||c>57;c=getchar()) if(!(c^45))f=-1; for(;c>47&&c<58;c=getchar()) x=(x<<1)+(x<<3)+c-48; return x*f; } struct nt{ nt*ch[2],*p; bool rev;int cov; int size,sum,v,lmx,rmx,mmx; bool d(){return this==p->ch[1];} void setc(nt*c,int d){ ch[d]=c; c->p=this; } void revIt(){ rev^=1; swap(lmx,rmx); swap(ch[0],ch[1]); } void covIt(int co){ cov=v=co; sum=co*size; co>0?lmx=rmx=mmx=sum: lmx=rmx=mmx=co; } void pu(){ size=1+ch[0]->size+ch[1]->size; sum=v+ch[0]->sum+ch[1]->sum; lmx=max(ch[0]->lmx,ch[0]->sum+v+max(ch[1]->lmx,0)); rmx=max(ch[1]->rmx,ch[1]->sum+v+max(ch[0]->rmx,0)); mmx=max(max(ch[0]->mmx,ch[1]->mmx),max(ch[0]->rmx,0)+v+max(ch[1]->lmx,0)); } void relax(){ if(rev) ch[0]->revIt(), ch[1]->revIt(); if(cov^inf) ch[0]->covIt(cov), ch[1]->covIt(cov); rev=0; cov=inf; } }; nt*null=new nt(); nt*root=null; int n,a[N],m; char sign[10]; nt*newnode(nt*p,int v){ nt*o=new nt(); o->size=1; o->v=o->sum=o->lmx=o->rmx=o->mmx=v; o->ch[0]=o->ch[1]=null; o->cov=inf; o->p=p; return o; } void rot(nt*&o){ nt*p=o->p; p->relax(); o->relax(); bool d=o->d(); p->p->setc(o,p->d()); p->setc(o->ch[!d],d); o->setc(p,!d); p->pu();o->pu(); if(p==root)root=o; } void splay(nt*o,nt*p){ while(o->p!=p) if(o->p->p==p) rot(o); else o->d()^o->p->d()?(rot(o),rot(o)):(rot(o->p),rot(o)); o->pu(); } nt*build(int x,int y){ if(x>y)return null; nt*o=newnode(o,a[mid]); o->setc(build(x,mid-1),0); o->setc(build(mid+1,y),1); o->pu(); return o; } void del(nt*&o){ if(o->ch[0]!=null)del(o->ch[0]); if(o->ch[1]!=null)del(o->ch[1]); delete o; } nt*kth(int k){ for(nt*o=root;;){ o->relax(); if(k<=o->ch[0]->size) o=o->ch[0]; else{ k-=o->ch[0]->size+1; if(!k)return o; o=o->ch[1]; } } } int main(){ n=Rin(),m=Rin(); for(int i=1;i<=n;i++)a[i]=Rin(); root=build(0,n+1); root->p=null; int x,y,z; while(m--){ scanf("%s",sign); switch(sign[2]){ case‘S‘: x=Rin(),y=Rin(); for(int i=1;i<=y;i++)a[i]=Rin(); splay(kth(x+1),null); splay(kth(x+2),root); root->ch[1]->setc(build(1,y),0); root->ch[1]->pu(); root->pu(); break; case‘L‘: x=Rin(),y=Rin(); splay(kth(x),null); splay(kth(x+y+1),root); del(root->ch[1]->ch[0]); root->ch[1]->ch[0]=null; root->ch[1]->pu(); root->pu(); break; case‘K‘: x=Rin(),y=Rin(),z=Rin(); splay(kth(x),null); splay(kth(x+y+1),root); root->ch[1]->ch[0]->covIt(z); root->ch[1]->pu(); root->pu(); break; case‘T‘: x=Rin(),y=Rin(); splay(kth(x),null); splay(kth(x+y+1),root); printf("%d\n",root->ch[1]->ch[0]->sum); break; case‘V‘: x=Rin(),y=Rin(); splay(kth(x),null); splay(kth(x+y+1),root); root->ch[1]->ch[0]->revIt(); root->ch[1]->pu(); root->pu(); break; case‘X‘: splay(kth(1),null); splay(kth(root->size),root); printf("%d\n",root->ch[1]->ch[0]->mmx); break; default:break; } } return 0; }
以上是关于[bzoj1500][NOI2005 维修数列] (splay区间操作)的主要内容,如果未能解决你的问题,请参考以下文章