問題の意味: デジタル・シーケンスが与えられると、動作の6つのモードがある:
(1)ADDのXYD:X-Yの第二の数を加えた数Dへ。
(2)逆XY:[X、Y]がひっくり返される間隔の数。
(3)XYT REVOLVE:区間[x、y] T番目の回転。
(4)INSERT XP:最初の番号Xの後に挿入P。
(5)DELETE X:X最初の番号を削除します。
(6)MINのXY:クエリー間隔[X、Y]は最小です。
アイデア:区間[L、R]のためのスプレイボードのタイトル、ルーツにL-1スピン、R + 1のスピンは、右の子のルートで、その後、左部分木の1が区間[L、R]である+ R。
我々は、サブツリーに治療期間の後に間隔を置い保存し、削除することができますので、回転部は、前面に前の段落の後、再治療期間を2つのセクションに分かれて、それを交換しています。
#include<cstdio>
#include<iostream>
using namespace std;
const int maxx = 2e5+10;
const int inf = 0x3f3f3f3f;
int ch[maxx][2],fa[maxx],siz[maxx],key[maxx];
int rev[maxx],lazy[maxx],w[maxx],mi[maxx];
int rt,sz;
char s[20];
int get(int x)
{
return ch[fa[x]][1]==x;
}
void update(int x)
{
if(!x)return;
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
mi[x]=key[x];
if(ch[x][0])mi[x]=min(mi[x],mi[ch[x][0]]);
if(ch[x][1])mi[x]=min(mi[x],mi[ch[x][1]]);
}
void pushdown(int x)
{
if(!x)return;
if(rev[x])
{
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]=0;
}
if(lazy[x])
{
lazy[ch[x][0]]+=lazy[x];
lazy[ch[x][1]]+=lazy[x];
key[ch[x][0]]+=lazy[x];
key[ch[x][1]]+=lazy[x];
mi[ch[x][0]]+=lazy[x];
mi[ch[x][1]]+=lazy[x];
lazy[x]=0;
}
}
void rotate(int x)
{
int y=fa[x],z=fa[y],k=get(x);
pushdown(x);pushdown(y);
ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
ch[x][k^1]=y;fa[y]=x;fa[x]=z;
if(z)ch[z][ch[z][1]==y]=x;
update(y);update(x);
}
void splay(int x,int goal)
{
for(int y;(y=fa[x])!=goal;rotate(x))
if(fa[y]!=goal)rotate((get(x)==get(y))?y:x);
if(goal==0)rt=x; //注意
}
int findkth(int k) //找第k个节点
{
int x=rt;
while(1)
{
pushdown(x);
if(k<=siz[ch[x][0]])x=ch[x][0];
else
{
k-=siz[ch[x][0]]+1;
if(!k)return x;
x=ch[x][1];
}
}
}
int build(int l,int r,int f)
{
if(l>r)return 0;
int mid=(l+r)/2;
int x=++sz;
fa[x]=f;
key[x]=w[mid];
ch[x][0]=build(l,mid-1,x);
ch[x][1]=build(mid+1,r,x);
update(x);
return x;
}
void add(int l,int r,int val) //区间加
{
int x=findkth(l-1),y=findkth(r+1);
splay(x,0);splay(y,x);
int tmp=ch[ch[rt][1]][0];
key[tmp]+=val;
mi[tmp]+=val;
lazy[tmp]+=val;
update(ch[rt][1]);
update(rt);
}
void Insert(int k,int val) //在第k个数后插入值为x的节点
{
int x=findkth(k),y=findkth(k+1);
splay(x,0);splay(y,x);
ch[ch[rt][1]][0]=++sz;
fa[sz]=ch[rt][1];
key[sz]=mi[sz]=val;
siz[sz]=1;
update(ch[rt][1]);
update(rt);
}
void Delete(int k) //删除第k个节点
{
int x=findkth(k-1),y=findkth(k+1);
splay(x,0);splay(y,x);
ch[ch[rt][1]][0]=0;
update(ch[rt][1]);
update(rt);
}
void Reverse(int l,int r) //区间翻转
{
int x=findkth(l-1),y=findkth(r+1);
splay(x,0); //x旋转为根
splay(y,x); //y旋转为根的右孩子
//旋转完之后y的左子树为区间[l,r]
rev[ch[ch[rt][1]][0]]^=1; //lazy标记是否要旋转其左右子树
}
void revolve(int l1,int r1,int l2,int r2) //区间旋转
{
int x=findkth(l2-1),y=findkth(r2+1);
splay(x,0);splay(y,x);
int tmp=ch[ch[rt][1]][0];ch[ch[rt][1]][0]=0;
update(ch[rt][1]);update(rt);
x=findkth(l1-1);y=findkth(l1);
splay(x,0);splay(y,x);
ch[ch[rt][1]][0]=tmp;
fa[tmp]=ch[rt][1];
update(ch[rt][1]);update(rt);
}
int getmi(int l,int r) //找区间最小值
{
int x=findkth(l-1),y=findkth(r+1);
splay(x,0);splay(y,x);
return mi[ch[ch[rt][1]][0]];
}
int main()
{
int n,m;
scanf("%d",&n);
w[1]=-inf;w[n+2]=inf;
for(int i=2;i<=n+1;i++)scanf("%d",&w[i]);
rt=build(1,n+2,0);
scanf("%d",&m);
int x,y,z;
while(m--)
{
scanf("%s",s);
if(s[0]=='A')scanf("%d%d%d",&x,&y,&z),add(x+1,y+1,z);
else if(s[0]=='I')scanf("%d%d",&x,&y),Insert(x+1,y);
else if(s[0]=='D')scanf("%d",&x),Delete(x+1);
else if(s[0]=='M')scanf("%d%d",&x,&y),printf("%d\n",getmi(x+1,y+1));
else if(s[3]=='E')scanf("%d%d",&x,&y),Reverse(x+1,y+1);
else
{
scanf("%d%d%d",&x,&y,&z);
z=z%(y-x+1);
if(z)revolve(x+1,y-z+1,y-z+2,y+1);
}
}
return 0;
}