题面
解析
合并序列相邻的两点,在序列中插入一个点,直接考虑Splay
先考虑如何完成操作3, 4
对于操作3,显然是区间最大减去区间最小,Splay维护一下即可
对于操作4,实际上就是求区间内相邻两数的差的绝对值的最小值(注意是绝对值,我一开始就写错了), 那么每个节点还需要维护当前点与它前驱的差的绝对值,查询$[l, r]$的答案,实际上是在Splay的$[l+1, r]$节点中查询
操作1:把x旋转至根,把x+2旋转至根的右儿子,x+1就是x+2的左儿子,直接删除。因为相邻两数的差也变了,所以先更新x+2的信息,再更新x的信息
操作2:把x旋转至根,x+1就是它的后继,在后继的左儿子新开一个节点,存信息,相邻两数的差改变了,所以后继的信息也要更新,再把新开的节点旋转至根,完成整颗Splay的信息更新
代码:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100004;
template<class T> void read(T &re)
{
re=0;
T sign=1;
char tmp;
while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;
re=tmp-'0';
while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');
re*=sign;
}
int n, m, root, tot;
int a[maxn];
struct splay_tree{
int fa, s[2], siz;
int val, mx, mn, mu, b;
}tr[maxn<<1];
void update(int x)
{
int ls = tr[x].s[0], rs = tr[x].s[1];
tr[x].siz = tr[ls].siz + tr[rs].siz + 1;
tr[x].mx = tr[x].mn = tr[x].val;
tr[x].mu = tr[x].b;
if(ls)
{
tr[x].mx = max(tr[x].mx, tr[ls].mx);
tr[x].mn = min(tr[x].mn, tr[ls].mn);
tr[x].mu = min(tr[x].mu, tr[ls].mu);
}
if(rs)
{
tr[x].mx = max(tr[x].mx, tr[rs].mx);
tr[x].mn = min(tr[x].mn, tr[rs].mn);
tr[x].mu = min(tr[x].mu, tr[rs].mu);
}
}
void Rotate(int x)
{
int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];
tr[y].s[k] = son;tr[son].fa = y;
tr[x].s[k^1] = y;tr[y].fa = x;
tr[z].s[w] = x;tr[x].fa = z;
update(y);update(x);
}
void Splay(int x, int to)
{
int y, z;
while(tr[x].fa != to)
{
y = tr[x].fa;
z = tr[y].fa;
if(z != to)
Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y);
Rotate(x);
}
if(!to)
root = x;
}
void build(int l, int r, int ff)
{
int mid = (l + r)>>1;
if(l < mid)
build(l, mid - 1, mid);
if(mid < r)
build(mid + 1, r, mid);
if(ff)
tr[ff].s[ff < mid] = mid;
tr[mid].fa = ff;
tr[mid].val = a[mid];
tr[mid].b = abs(a[mid] - a[mid - 1]);
update(mid);
}
int Find(int x)
{
int now = root;
while(1)
{
int ls = tr[now].s[0], rs = tr[now].s[1];
if(x == tr[ls].siz + 1)
return now;
if(x > tr[ls].siz + 1)
x -= tr[ls].siz + 1, now = rs;
else
now = ls;
}
}
int Findpre()
{
int now = tr[root].s[0];
if(!now) return 0;
while(tr[now].s[1]) now = tr[now].s[1];
return now;
}
int Findnxt()
{
int now = tr[root].s[1];
if(!now) return 0;
while(tr[now].s[0]) now = tr[now].s[0];
return now;
}
int main()
{
read(n);read(m);
for(int i = 1; i <= n; ++i)
read(a[i+1]);
n += 2;
build(1, n, 0);
tr[0].s[1] = root = (1 + n)>>1;
tot = n;
for(int i = 1; i <= m; ++i)
{
char opt[8];
scanf("%s", opt);
if(opt[1] == 'e')
{
int x, e;
read(x);read(e);
x++;
int now = Find(x);
Splay(now, 0);
int pre = Findpre();
tr[now].b = abs(e - tr[pre].val);
tr[now].val = e;
int nnxt = Find(x + 2);
Splay(nnxt, now);
tr[nnxt].b = abs(tr[nnxt].val - e);
tr[nnxt].s[0] = 0;
update(nnxt);update(now);
}
else if(opt[0] == 'i')
{
int x, e;
read(x);read(e);
x++;
int now = Find(x);
Splay(now, 0);
int nxt = Findnxt();
tr[nxt].s[0] = ++tot;
tr[tot].val = e;
tr[tot].fa = nxt;
tr[tot].b = abs(e - tr[now].val);
tr[nxt].b = abs(tr[nxt].val - e);
Splay(tot, 0);
}
else if(opt[1] =='a')
{
int x, y;
read(x);read(y);
x++;y++;
x = Find(x - 1);
y = Find(y + 1);
Splay(x, 0);
Splay(y, x);
int now = tr[y].s[0];
printf("%d\n", tr[now].mx - tr[now].mn);
}
else
{
int x, y;
read(x);read(y);
x += 2;
y++;
x = Find(x - 1);
y = Find(y + 1);
Splay(x, 0);
Splay(y, x);
int now = tr[y].s[0];
printf("%d\n", tr[now].mu);
}
}
return 0;
}
