这道题的操作非常多
ADD操作和REVERSE操作一样, 把区间变成子树, 然后直接加标记就可以了
REVOLVE 看起来很厉害, 稍微分析一下就可以得出其实就是把区间后面的一部分和放到前面一部分的前面
INSERT 操作可以把插入点之前的结点转到根结点, 插入点之后的结点转到根节点下面, 这样插入的位置就一定是根节点右儿子的左儿子(方便操作, 人为给splay tree加上两个端点结点)
DELETE 操作可以先把删除的结点转成一颗子树, 然后直接删掉就好
MIN 操作也类似, 直接把区间转成子树, 直接出解
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200015;
const int INF = 0x7f7f7f7f;
#define KT ch[ch[root][1]][0]
int root, fa[N], sz[N], ch[N][2];
bool rev[N];
int sum[N], mi[N], num[N];
int tot;
inline void pushup(int x)
{
int l = ch[x][0], r = ch[x][1];
sz[x] = 1 + sz[l] + sz[r];
mi[x] = min(mi[l], mi[r]);
mi[x] = min(mi[x], num[x]);
}
inline void pushdown(int x)
{
int &l = ch[x][0], &r = ch[x][1];
if(rev[x])
{
rev[l] ^= 1;
rev[r] ^= 1;
rev[x] = false;
swap(l, r);
}
if(sum[x])
{
sum[l] += sum[x];
sum[r] += sum[x];
if(l) //不加会错, 应该是INF设置的太大, 直接+的话, mi[0]会+爆, 导致以后更新出错
{
mi[l] += sum[x];
num[l] += sum[x];
}
if(r)
{
mi[r] += sum[x];
num[r] += sum[x];
}
sum[x] = 0;
}
}
void build(int l, int r, int f)
{
if(l > r)
return ;
int m = (l + r) >> 1; //m是当前结点
ch[m][0] = (m - 1 >= l)? (m - 1 + l) >> 1: 0;
ch[m][1] = (r >= m + 1)? (m + 1 + r) >> 1: 0;
mi[m] = num[m];
fa[m] = f;
build(l, m - 1, m);
build(m + 1, r, m);
pushup(m);
}
void init()
{
memset(rev, false, sizeof(rev)); //反转的懒惰标记
memset(sum, 0, sizeof(sum)); //add的懒惰标记
sz[0] = 0;
root = (1 + tot) >> 1;
build(1, tot, 0);
}
inline void rotate(int x, bool f)
{
int y = fa[x];
int z = fa[y];
pushdown(y);
pushdown(x);
ch[y][!f] = ch[x][f];
fa[ch[x][f]] = y;
fa[x] = z;
if(z)
ch[z][ch[z][1] == y] = x;
ch[x][f] = y;
fa[y] = x;
pushup(y);
}
void splay(int x, int g)
{
int y = fa[x];
pushdown(x);
while(y != g)
{
int z = fa[y];
bool f = ch[y][0] == x;
if(z != g && f == (ch[z][0] == y))
rotate(y, f);
rotate(x, f);
y = fa[x];
}
pushup(x);
if(g == 0)
root = x;
}
void rotateto(int k, int g)
{
int x = root;
pushdown(x);
while(sz[ch[x][0]] != k)
{
if(k < sz[ch[x][0]])
x = ch[x][0];
else
{
k -= sz[ch[x][0]] + 1;
x = ch[x][1];
}
pushdown(x);
}
splay(x, g);
}
void add(int a, int b, int c)
{
rotateto(a - 1, 0);
rotateto(b + 1, root);
num[KT] += c;
mi[KT] += c;
sum[KT] += c;
}
void rever(int a, int b)
{
rotateto(a - 1, 0);
rotateto(b + 1, root);
rev[KT] ^= 1;
}
void revolve(int a, int b, int c)
{
if(c == 0 || a == b)
return ;
int t = c % (b - a + 1);
if(t == 0)
return ;
int _a = b - t + 1 //[_a, b]要放到[a, _a - 1]前面;
rotateto(_a - 1, 0);
rotateto(b + 1, root);
int tmp = KT;
KT = 0;
pushup(ch[root][1]);
pushup(root);
rotateto(a - 1, 0);
rotateto(a, root);
KT = tmp;
fa[tmp] = ch[root][1];
pushup(ch[root][1]);
pushup(root);
}
void inster(int a, int b)
{
rotateto(a, 0);
rotateto(a + 1, root);
num[++tot] = b;
sz[tot] = 1;
ch[tot][0] = ch[tot][1] = 0;
fa[tot] = ch[root][1];
KT = tot;
mi[tot] = b;
pushup(ch[root][1]);
pushup(root);
}
void delet(int a)
{
rotateto(a - 1, 0);
rotateto(a + 1, root);
KT = 0;
pushup(ch[root][1]);
pushup(root);
}
int getmin(int a, int b)
{
rotateto(a - 1, 0);
rotateto(b + 1, root);
return mi[KT];
}
int main()
{
int n;
while(~scanf("%d", &n))
{
mi[0] = INF; //这里要注意
tot = 0;
num[1] = INF; //左端点
tot = n + 2;
for(int i = 2; i < tot; i++)
scanf("%d", num + i);
num[tot] = INF; //右端点
init(); //建树
int m;
scanf("%d", &m);
while(m--)
{
char s[10];
scanf("%s", s);
int a, b, c;
if(s[0] == 'A')
{
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
else if(s[0] == 'R')
{
scanf("%d%d", &a, &b);
if(s[3] == 'E')
rever(a, b);
else
{
scanf("%d", &c);
revolve(a, b, c);
}
}
else if(s[0] == 'I')
{
scanf("%d%d", &a, &b);
inster(a, b);
}
else if(s[0] == 'D')
{
scanf("%d", &a);
delet(a);
}
else
{
scanf("%d%d", &a, &b);
printf("%d\n", getmin(a, b));
}
}
}
return 0;
}