题意:对于一个序列有若干的操作 分别为插入、删除 单个数,翻转序列,使中间一段序列进行指定的循环移位、
查询区间最小值
解法:对于splay来说插入、删除、翻转已经是很简单的操作了,查询最小值更是比线段树还简单
,这一道题目的难点就在于循环移位
这里就有一个绝妙的解释办法:
假设我们在区间[l,r]要循环移位的数为k位
那么最后等价的结果是[r-k+1,r][l,l+k-1]
现在我们把它倒过来看就是 [l+k-1,l][r,r-k+1]这其实是两个区间各自的翻转!
那么我们可以把循环移位分成
翻转区间[l,l+k-1] 翻转区间 [r-k+1,r] 最后翻转整个区间即可
#include<stdio.h>
#include<string.h>
#include<limits.h>
#include<iostream>
using namespace std;
#define ls ch[rt][0]
#define rs ch[rt][1]
#define rls ch[root][0]
#define rrs ch[root][1]
#define inf ~0U>>2
#define maxn 222222
int fa[maxn],ch[maxn][2],num[maxn],mi[maxn],add[maxn],va[maxn],rev[maxn];
int cnt,root;
inline void down(int rt){
if(rev[rt]){
swap(ls,rs);
if(ls)rev[ls]^=1;
if(rs)rev[rs]^=1;
rev[rt]=0;
}if(add[rt]){
int w=add[rt];
if(ls)add[ls]+=w,mi[ls]+=w,va[ls]+=w;
if(rs)add[rs]+=w,mi[rs]+=w,va[rs]+=w;
add[rt]=0;
}
}
inline void up(int rt){
mi[rt]=inf;
mi[rt]=min(min(mi[ls],mi[rs]),va[rt]);
num[rt]=num[ls]+num[rs]+1;
}
inline void rot(int rt){
int f=fa[rt],side=ch[f][1]==rt,&ll=ch[rt][!side];
fa[ll]=f,ch[f][side]=ll;
fa[rt]=fa[f],ch[fa[f]][ch[fa[f]][1]==f]=rt;
fa[f]=rt,ch[rt][!side]=f;
up(f),up(rt);
}
inline void splay(int rt,int aim){
while(fa[rt]!=aim){
int f=fa[rt],ff=fa[f];
if(ff==aim)rot(rt);
else if((ch[ff][1]==f)==(ch[f][1]==rt))rot(f),rot(rt);
else rot(rt),rot(rt);
}if(!aim)root=rt;
}
inline void find(int sub,int tot){
int rt=sub;
while(1){
down(rt);
if(num[ls]==tot-1)break;
if(num[ls]>=tot)rt=ls;
else tot-=num[ls]+1,rt=rs;
}
splay(rt,fa[sub]);
}
void _add(int l,int r,int w){
find(root,l);
find(rrs,r-l+2);
int rt=ch[rrs][0];
add[rt]+=w,mi[rt]+=w,va[rt]+=w;
up(fa[rt]);up(root);
}
int query(int l,int r){
find(root,l);
find(rrs,r-l+2);
return mi[ch[rrs][0]];
}
void ins(int l,int w){
find(root,l+1);
down(root);
fa[rrs]=++cnt,ch[cnt][1]=rrs,ch[cnt][0]=0;
fa[cnt]=root,rrs=cnt;
va[cnt]=w;
up(cnt),up(root);
}
void del(int l){
find(root,l+1),find(rrs,1);
down(root);
fa[rls]=rrs,ch[rrs][0]=rls;
fa[rrs]=0,root=rrs;
up(root);
}
void flip(int l,int r){
find(root,l),find(rrs,r-l+2);
rev[ch[rrs][0]]^=1;
}
void wheel(int l,int r,int tt){
if(!tt)return ;
int t=(tt%(r-l+1)+(r-l+1))%(r-l+1);
if(t==r)return ;
flip(l,r-t);
flip(r-t+1,r);
flip(l,r);
}
int n,m,a,b,c;
char op[11];
int main()
{
scanf("%d",&n);
va[0]=mi[0]=va[1]=mi[1]=inf;
root=cnt=num[1]=1;
while(n--){
scanf("%d",&a);
va[++cnt]=a;num[cnt]=cnt;
ch[cnt][0]=cnt-1,fa[cnt-1]=cnt;
mi[cnt]=min(a,mi[cnt-1]);
}
root=cnt;
va[++cnt]=inf,num[cnt]=1;
ch[cnt-1][1]=cnt,fa[cnt]=cnt-1;mi[cnt]=inf;
num[root]=cnt;
scanf("%d",&m);
while(m--){
scanf("%s%d",op,&a);
if(op[0]=='A')scanf("%d%d",&b,&c),_add(a,b,c);
else if(op[0]=='I')scanf("%d",&b),ins(a,b);
else if(op[0]=='D')del(a);
else if(op[0]=='M')scanf("%d",&b),printf("%d\n",query(a,b));
else if(op[3]=='E')scanf("%d",&b),flip(a,b);
else scanf("%d%d",&b,&c),wheel(a,b,c);
}
return 0;
}