题目链接:https://cn.vjudge.net/problem/POJ-3580#author=0
伸展树学习:
很全:https://blog.csdn.net/qq_33184171/article/details/73549164
图:https://blog.csdn.net/wr132/article/details/50599747
效率:https://www.cnblogs.com/vamei/archive/2013/03/21/2964092.html
链接:dongxicheng.org/structure/splay-tree/
#include <iostream>
#include <cstdio>
using namespace std;
#define INF 2e9 + 10
const int N = 2e5 + 10;
struct Splaytree {
int nex[N][2];
int f[N];
int sz[N]; // 子树节点个数
int val[N]; // 当前节点的值
int cnt[N]; // 当前节点个数
int laz[N]; // 添加标记
int rev[N]; // 翻转标记
int minn[N];
int root;
int tot;
void init() {
root = 0;
tot = 0;
f[0] = sz[0] = nex[0][0] = nex[0][1] = 0;
rev[0] = laz[0] = 0;
cnt[0] = 0;
}
void newnode(int rt, int v, int fa) {
f[rt] = fa;
sz[rt] = 1;
val[rt] = v;
cnt[rt] = 1;
minn[rt] = v;
laz[rt] = 0;
nex[rt][0] = nex[rt][1] = 0;
}
void delnode(int rt) {
f[rt] = sz[rt] = val[rt] = cnt[rt] = 0;
nex[rt][0] = nex[rt][1] = 0;
}
void pushup(int rt) {
if(!rt) return;
sz[rt] = cnt[rt];
minn[rt] = val[rt];
if(nex[rt][0]) sz[rt] += sz[nex[rt][0]], minn[rt] = min(minn[rt], minn[nex[rt][0]]);
if(nex[rt][1]) sz[rt] += sz[nex[rt][1]], minn[rt] = min(minn[rt], minn[nex[rt][1]]);
}
void build(int &rt, int l, int r, int fa) { // 构建
if(l > r) return;
int mid = (l + r) >> 1;
rt = mid;
minn[rt] = val[rt];
newnode(rt, val[rt], fa);
cnt[rt] = 1;
build(nex[rt][0], l, mid - 1, rt);
build(nex[rt][1], mid + 1, r, rt);
pushup(rt);
}
void update_add(int rt, int v) { // 更新
if(rt) {
laz[rt] += v;
val[rt] += v;
minn[rt] += v;
}
}
void update_rev(int rt) {
if(rt) {
nex[rt][0] ^= nex[rt][1] ^= nex[rt][0] ^= nex[rt][1];
rev[rt] ^= 1;
}
}
void pushdown(int rt) {
if(!rt) return;
if(laz[rt]) {
update_add(nex[rt][0], laz[rt]);
update_add(nex[rt][1], laz[rt]);
laz[rt] = 0;
}
if(rev[rt]) {
update_rev(nex[rt][0]);
update_rev(nex[rt][1]);
rev[rt] = 0;
}
}
void rotate(int x, int k) { // 0:左旋 1:右旋
int y = f[x];
int z = f[y];
pushdown(y);
pushdown(x);
nex[y][!k] = nex[x][k];
if(nex[x][k]) f[nex[x][k]] = y;
f[x] = z;
if(z) nex[z][nex[z][1] == y] = x;
f[y] = x;
nex[x][k] = y;
pushup(y);
pushup(x);
}
void splay(int x, int goal) { // x 旋转到 goal下面
while(f[x] != goal) {
if(f[f[x]] == goal) rotate(x, nex[f[x]][0] == x);
else {
int y = f[x], z = f[y];
int K = (nex[z][0] == y);
if(nex[y][K] == x) rotate(x, !K), rotate(x, K);
else rotate(y, K), rotate(x, K);
}
}
pushup(x);
if(goal == 0) root = x;
}
int search(int rt, int x) { // 查询权值为x的节点
if(nex[rt][0] && val[rt] > x) return search(nex[rt][0], x);
else if(nex[rt][1] && val[rt] < x) return search(nex[rt][1], x);
else return rt;
}
int extreme(int rt, int k) { // 子树最值节点 0小 1大
while(nex[rt][k]) rt = nex[rt][k];
splay(rt, 0);
return rt;
}
int getkth(int rt, int k) { // 得到第k个
pushdown(rt);
if(sz[nex[rt][0]] < k && k <= sz[nex[rt][0]] + cnt[rt]) return rt;
else if(sz[nex[rt][0]] >= k) return getkth(nex[rt][0], k);
else return getkth(nex[rt][1], k - sz[nex[rt][0]] - cnt[rt]);
}
int prec(int x) { // 前驱
int k = search(root, x);
splay(k, 0);
if(val[k] < x) return k;
return extreme(nex[k][0], 1);
}
int sufc(int x) { // 后继
int k = search(root, x);
splay(k, 0);
if(val[k] > x) return k;
return extreme(nex[k][1], 0);
}
void insert(int x) { // 插入 不管序列 只用权值
int y = search(root, x);
if(val[y] == x) {
cnt[y]++;
sz[y]++;
for(int k = y; k; k = f[k]) pushup(k);
splay(y, 0);
} else {
int p = prec(x);
int s = sufc(x);
splay(p, 0);
splay(s, p);
newnode(++tot, x, nex[root][1]);
nex[nex[root][1]][0] = tot;
for(int k = nex[root][1]; k; k = f[k]) pushup(k);
}
}
void insert_k(int k, int x) { // 第k个后面插一个数 按照序列
int l = getkth(root, k);
int r = getkth(root, k + 1);
splay(l, 0);
splay(r, l);
newnode(++tot, x, r);
nex[r][0] = tot;
for(int k = r; k; k = f[k]) pushdown(k), pushup(k);
splay(r, 0);
}
void delete_(int x) { // 删除 某权值
int y = search(root, x);
if(val[y] != x) return;
if(cnt[y] > 1) {
cnt[y]--;
sz[y]--;
for(int k = y; k; k = f[k]) pushup(k);
} else if(nex[y][0] == 0 || nex[y][1] == 0) {
int z = f[y];
nex[z][nex[z][1] == y] = nex[y][nex[y][0] == 0];
f[nex[y][nex[y][0] == 0]] = z;
delnode(y);
for(int k = z; k; k = f[k]) pushup(k);
} else {
int p = prec(x);
int s = sufc(x);
splay(p, 0);
splay(s, p);
nex[nex[root][1]][0] = 0;
delnode(nex[nex[root][1]][0]);
for(int k = s; k; k = f[k]) pushup(k);
}
}
void delete_k(int k) { // 删除第k个
splay(getkth(root, k - 1), 0);
splay(getkth(root, k + 1), root);
nex[nex[root][1]][0] = 0;
delnode(nex[nex[root][1]][0]);
pushup(nex[root][1]);
pushup(root);
}
int getmin(int l, int r) { // 区间最小
int x = getkth(root, l - 1);
int y = getkth(root, r + 1);
splay(x, 0);
splay(y, x);
// cout << y << endl;
return minn[nex[y][0]];
}
int getrank(int x) { // 某权值的排名
int k = search(root, x);
splay(k, 0);
return sz[nex[k][0]] + 1;
}
void add(int l, int r, int v) { // 区间加
int x = getkth(root, l - 1);
int y = getkth(root, r + 1);
splay(x, 0);
splay(y, x);
update_add(nex[y][0], v);
}
void reversal(int l, int r) { // 区间翻转
int x = getkth(root, l - 1);
int y = getkth(root, r + 1);
splay(x, 0);
splay(y, x);
update_rev(nex[y][0]);
}
void exchange(int l1, int r1, int l2, int r2) { // 区间交换
int x = getkth(root, l2 - 1);
int y = getkth(root, r2 + 1);
splay(x, 0);
splay(y, x);
int tmp = nex[y][0];
nex[y][0] = 0;
x = getkth(root, l1 - 1);
y = getkth(root, l1);
splay(x, 0);
splay(y, x);
nex[y][0] = tmp;
f[tmp] = y;
}
int rt_left(int rt) { // 子树 最左
for(pushdown(rt); nex[rt][0]; pushdown(rt)) rt = nex[rt][0];
return rt;
}
int rt_right(int rt){ // 子树 最右
for(pushdown(rt); nex[rt][1]; pushdown(rt)) rt = nex[rt][1];
return rt;
}
void delete_rt() { // 删除 根节点
if(nex[root][0] == 0) {
root = nex[root][1];
f[root] = 0;
} else {
int y = rt_right(nex[root][0]);
splay(y, root);
nex[y][1] = nex[root][1];
f[nex[root][1]] = y;
root = y;
f[root] = 0;
pushup(root);
}
}
void pint(int rt){
if(!rt) return;
pushdown(nex[rt][0]);
pint(nex[rt][0]);
printf("%d f[] = %d sz[] = %d lson = %d rson = %d val[] = %d mi[] = %d \n",rt , f[rt], sz[rt], nex[rt][0], nex[rt][1], val[rt], minn[rt]);
pushdown(nex[rt][1]);
pint(nex[rt][1]);
pushup(rt);
}
void debug(){
printf("ROOT = %d <---\n",root);
pushdown(root);
pint(root);
}
}p;
int n, m;
int main() {
scanf("%d", &n);
p.init();
p.val[1] = -INF;
p.val[n + 2] = INF;
for(int i = 2; i <= n + 1; i++) scanf("%d", &p.val[i]);
p.tot = n + 2;
p.build(p.root, 1, n + 2, 0);
p.pushup(p.root);
scanf("%d", &m);
char op[10];
int l, r, x;
for(int i = 1; i <= m; i++) {
scanf("%s", op);
if(op[0] == 'A') {
scanf("%d %d %d", &l, &r, &x);
l++, r++;
p.add(l, r, x);
} else if(op[0] == 'I') {
scanf("%d %d", &l, &x);
l++;
p.insert_k(l, x);
} else if(op[0] == 'M') {
scanf("%d %d", &l, &r);
l++, r++;
printf("%d\n", p.getmin(l , r));
} else if(op[0] == 'D') {
scanf("%d", &l);
l++;
p.delete_k(l );
} else if(op[3] == 'E') {
scanf("%d %d", &l, &r);
l++, r++;
p.reversal(l, r);
} else {
scanf("%d %d %d", &l, &r, &x);
l++, r++;
x = x % (r - l + 1);
if(x) p.exchange(l, r - x, r - x + 1, r);
}
}
// p.debug();
return 0;
}