题面
解析
合并序列相邻的两点,在序列中插入一个点,直接考虑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的信息更新
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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 ", 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 ", tr[now].mu); } } return 0; }