题意:
给一个序列,对其进行各种操作。在对序列仅对操作的处理上,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;
}