题意:
给一个序列,对其进行各种操作。在对序列仅对操作的处理上,splay是比线段树强大的,虽然均摊复杂度均为logN,但它能支持1:在某个位置插入一些连续的数,2:在某个位置删除一些连续的数。只是splay随便一些200+行。
分析:
网上各种模板介绍漫天飞,这个还算简洁明了。
代码:
//poj 3580 #include <stdio.h> #define maxN 200000 int N,T,node; int a[maxN],size[maxN],left[maxN],right[maxN],pre[maxN],key[maxN],add[maxN],rev[maxN],minx[maxN]; void pushdown(int cur) { int ls=left[cur],rs=right[cur]; if(add[cur]){ add[ls]+=add[cur],add[rs]+=add[cur]; key[ls]+=add[cur],key[rs]+=add[cur]; minx[ls]+=add[cur],minx[rs]+=add[cur]; add[cur]=0; } if(rev[cur]){ rev[ls]=rev[ls]^1,rev[rs]=rev[rs]^1; left[cur]=rs,right[cur]=ls; rev[cur]=0; } } void update(int cur) { int ls=left[cur],rs=right[cur]; size[cur]=size[ls]+size[rs]+1; minx[cur]=key[cur]; if(ls&&minx[ls]<minx[cur]) minx[cur]=minx[ls]; if(rs&&minx[rs]<minx[cur]) minx[cur]=minx[rs]; } void newnode(int &cur,int v) { cur=++node; minx[cur]=key[cur]=v; size[cur]=1; left[cur]=right[cur]=rev[cur]=add[cur]=0; } void build(int &cur,int x,int y,int p) { int mid=(x+y)/2; newnode(cur,a[mid]); pre[cur]=p; if(x==y) return ; if(x<mid) build(left[cur],x,mid-1,cur); if(mid<y) build(right[cur],mid+1,y,cur); update(cur); } void init() { for(int i=1;i<=N;++i) scanf("%d",&a[i]); node=size[0]=left[0]=right[0]=pre[0]=0; build(T,0,N+1,0); } void leftrotate(int x) { int y=right[x],p=pre[x]; right[x]=left[y]; if(right[x]) pre[right[x]]=x; left[y]=x; pre[x]=y; pre[y]=p; if(p==0) T=y; else right[p]==x?right[p]=y:left[p]=y; update(x); } void rightrotate(int x) { int y=left[x],p=pre[x]; left[x]=right[y]; if(left[x]) pre[left[x]]=x; right[y]=x; pre[x]=y; pre[y]=p; if(p==0) T=y; else right[p]==x?right[p]=y:left[p]=y; update(x); } void splay(int x,int goal) { int y,z; while(1){ if((y=pre[x])==goal) break; if((z=pre[y])==goal) right[y]==x?leftrotate(y):rightrotate(y); else{ if(right[z]==y){ if(right[y]==x) leftrotate(z),leftrotate(y); else rightrotate(y),leftrotate(z); } else{ if(left[y]==x) rightrotate(z),rightrotate(y); else leftrotate(y),rightrotate(z); } } } update(x); } void rotateto(int k,int goal) { int i=T; while(1){ pushdown(i); if(size[left[i]]+1==k) break; if(k<=size[left[i]]) i=left[i]; else k-=size[left[i]]+1,i=right[i]; } splay(i,goal); } void ADD(int x,int y,int z) { int k; rotateto(x,0),rotateto(y+2,T); k=left[right[T]]; add[k]+=z,key[k]+=z,minx[k]+=z; } void REVERSE(int x,int y) { int k; rotateto(x,0),rotateto(y+2,T); k=left[right[T]]; rev[k]^=1; } void REVOLVE(int x,int y,int z) { int k=z%(y-x+1),t; if(k){ rotateto(x,0),rotateto(y+2-k,T); t=left[right[T]]; left[right[T]]=0; update(right[T]),update(T); rotateto(x+k,0),rotateto(x+k+1,T); left[right[T]]=t,pre[t]=right[T]; update(right[T]),update(T); } } void INSERT(int x,int y) { rotateto(x+1,0),rotateto(x+2,T); newnode(left[right[T]],y); pre[left[right[T]]]=right[T]; update(right[T]),update(T); } void DELETE(int x) { rotateto(x,0),rotateto(x+2,T); left[right[T]]=0; update(right[T]),update(T); } void MIN(int x,int y) { rotateto(x,0),rotateto(y+2,T); printf("%d\n",minx[left[right[T]]]); } void solve() { int x,y,z,m; char s[16]; scanf("%d",&m); while(m--){ scanf("%s",s); if(s[0]=='A'){ scanf("%d%d%d",&x,&y,&z); ADD(x,y,z); }else if(s[0]=='R'){ scanf("%d%d",&x,&y); if(s[3]=='E') REVERSE(x,y); else{ scanf("%d",&z); REVOLVE(x,y,z); } }else if(s[0]=='I'){ scanf("%d%d",&x,&y); INSERT(x,y); }else if(s[0]=='D'){ scanf("%d",&x); DELETE(x); }else if(s[0]=='M'){ scanf("%d%d",&x,&y); MIN(x,y); } } } int main() { while(scanf("%d",&N)==1){ init(); solve(); } return 0; }
时间: 2024-10-11 18:25:48