Splay
#include <splay.tree> #define cat Catherine
Splay依靠的并不是完全的平衡,根据90-10法则,90%的询问都发生在10%的数据上。
Splay的原理就是:找到询问频率最高的点,把它旋转到根节点,以此在下面的询问中提高效率。
我们认为,我正在访问的点就是询问频率最高的点。
让x成为树根(y):
1.如果y是x的父亲,向上旋x
2.如果x和x的父亲在树上偏的方向相同(左or右孩子),先让x的父亲向上旋,再旋x
3.else让x连续旋两次
//为什么分情况?可以自行画图看一看
//发现按照上述旋转,每次splay以后,整棵树十分的平衡!(接近于完全二叉树)
//如果不分情况,直接无脑上旋,则会结构变得比较乱
前驱、后继
首先,插入目标新节点,使该节点在根上
那么它的前驱为左子树中最大的那个
后继为右子树中最小的那个
最后,当然要删掉刚才插入的节点
文艺平衡树
建树:
就像给线段树建树一样,但是在原数组的基础上加一个-INF,+INF。(比如原序列是1,2,3,4。你建树的时候要给-INF,1,2,3,4,+INF建树)
至于为什么这样做,就是为了可以给区间[ 1,n ]倒置,还可以防止pre和nxt找不到
and then:
当操作到区间【l,r】的时候我们就把 l-1 旋到根的位置上去,再把 r + 1旋到根的右儿子位置处,如此,我们需要的区间【l,r】便都处在r+1的左儿子中了,然后有什么操作的话,我们就对区间进行标记来记录这个区间是否需要被翻转,实际上就是一直交换左右儿子,每个点维护的值最终被转到的位置就是树中序遍历之后的位置。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 5; const int mod = 1e9 + 7; const int INF = 2147483647; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct Splay_tree { int f, sub_size, cnt, val, tag; int son[2]; }s[maxn]; int orig[maxn], root, wz; inline bool which(int x) { return x == s[s[x].f].son[1]; } inline void update(int x) { if(x) { s[x].sub_size = s[x].cnt; if(s[x].son[0]) s[x].sub_size += s[s[x].son[0]].sub_size; if(s[x].son[1]) s[x].sub_size += s[s[x].son[1]].sub_size; } } inline void pushdown(int x) { if(x && s[x].tag) { s[s[x].son[1]].tag ^= 1; s[s[x].son[0]].tag ^= 1; swap(s[x].son[1], s[x].son[0]); s[x].tag = 0; } } inline void rotate(int x) { int fnow = s[x].f, ffnow = s[fnow].f; pushdown(x), pushdown(fnow); bool w = which(x); s[fnow].son[w] = s[x].son[w^1]; s[s[fnow].son[w]].f = fnow; s[fnow].f = x; s[x].f = ffnow; s[x].son[w^1] = fnow; if(ffnow) { s[ffnow].son[s[ffnow].son[1]==fnow] = x; } update(fnow); } inline void splay(int x, int goal) { for(int qwq; (qwq=s[x].f)!=goal; rotate(x)) { if(s[qwq].f != goal) { rotate(which(x) == which(qwq) ? qwq : x); } } if(goal == 0) { root = x; } } int build_tree(int l, int r, int fa) { if(l > r) return 0; int mid = (l + r) >> 1; int now = ++wz; s[now].f = fa; s[now].son[0] = s[now].son[1] = 0; s[now].cnt++; s[now].val = orig[mid]; s[now].sub_size++; s[now].son[0] = build_tree(l, mid-1, now); s[now].son[1] = build_tree(mid+1, r, now); update(now); return now; } inline int find(int x)//GetvalByRank { int now = root; while(1) { pushdown(now); if(x <= s[s[now].son[0]].sub_size) { now = s[now].son[0]; } else { x -= s[s[now].son[0]].sub_size + 1; if(!x) return now; now = s[now].son[1]; } } } inline void reverse(int x, int y) { int l = x - 1, r = y + 1; l = find(l), r = find(r); splay(l, 0); splay(r, l); int pos = s[root].son[1]; pos = s[pos].son[0]; s[pos].tag ^= 1; } inline void dfs(int now) { pushdown(now); if(s[now].son[0]) dfs(s[now].son[0]); if(s[now].val != -INF && s[now].val != INF) { printf("%d ", s[now].val); } if(s[now].son[1]) dfs(s[now].son[1]); } int main() { int n, m, x, y; scanf("%d%d", &n, &m); orig[1] = -INF; orig[n+2] = INF; for(int i=1; i<=n; i++) { orig[i+1] = i; } root = build_tree(1, n+2, 0); for(int i=1; i<=m; i++) { scanf("%d%d", &x, &y); reverse(x+1, y+1); } dfs(root); return 0; }
splay(x, y)的含义是向上翻转x直到x的father变成y
注意:以上代码中rotate函数里只update了fnow可能导致x的sub_size出错,但是不知道为什么对于这道题的答案没有影响,大部分的题解都会在后面加一个update(x),经验证加上当然还是对的。
[Splay伸展树]splay树入门级教程_SKY的C的博客-CSDN博客
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 5; const int mod = 1e9 + 7; const int INF = 2147483647; int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct Splay_tree { int f, sub_size, cnt, val, tag; int son[2]; }s[maxn]; int orig[maxn], root, wz; int n, a1, sum; bool flag; inline bool which(int x) { return x == s[s[x].f].son[1]; } inline void update(int x) { if(x) { s[x].sub_size = s[x].cnt; if(s[x].son[0]) s[x].sub_size += s[s[x].son[0]].sub_size; if(s[x].son[1]) s[x].sub_size += s[s[x].son[1]].sub_size; } } inline void rotate(int x) { int fnow = s[x].f, ffnow = s[fnow].f; bool w = which(x); s[fnow].son[w] = s[x].son[w^1]; s[s[fnow].son[w]].f = fnow; s[fnow].f = x; s[x].f = ffnow; s[x].son[w^1] = fnow; if(ffnow) { s[ffnow].son[s[ffnow].son[1]==fnow] = x; } update(fnow); update(x); } inline void splay(int x, int goal) { for(int qwq; (qwq=s[x].f)!=goal; rotate(x)) { if(s[qwq].f != goal) { rotate(which(x) == which(qwq) ? qwq : x); } } if(goal == 0) { root = x; } } int build_tree(int l, int r, int fa) { if(l > r) return 0; int mid = (l + r) >> 1; int now = ++wz; s[now].f = fa; s[now].son[0] = s[now].son[1] = 0; s[now].cnt++; s[now].val = orig[mid]; s[now].sub_size++; s[now].son[0] = build_tree(l, mid-1, now); s[now].son[1] = build_tree(mid+1, r, now); update(now); return now; } void BST_insert(int dat, int x) { if(dat == s[x].val) { flag = false; splay(x, 0); return; } if(dat < s[x].val) { if(s[x].son[0] == 0) { s[x].son[0] = wz; s[wz].f = x; s[wz].val = dat; //s[wz].son[0] = s[wz].son[1] = 0; } else BST_insert(dat, s[x].son[0]); } else { if(s[x].son[1] == 0) { s[x].son[1] = wz; s[wz].f = x; s[wz].val = dat; } else BST_insert(dat, s[x].son[1]); } } int get_pre(int x) { int y = s[x].son[0]; if(y == 0) return -1; while(s[y].son[1] != 0) y = s[y].son[1]; return y; } int get_nxt(int x) { int y = s[x].son[1]; if(y == 0) return -1; while(s[y].son[0] != 0) y = s[y].son[0]; return y; } void insert(int dat) { flag = true; wz++; BST_insert(dat, root); if(flag == false) return; splay(wz, 0); int pre = get_pre(wz), nxt = get_nxt(wz); //printf("pre=%d nxt=%d\n", pre, nxt); int Min = INF; if(pre != -1) Min = min(Min, dat-s[pre].val); if(nxt != -1) Min = min(Min, s[nxt].val-dat); sum += Min; //printf("sum=%d\n", sum); } int main() { //freopen("1.txt", "r", stdin); //orig[1] = -INF; orig[2] = INF; //root = build_tree(1, 2, 0); scanf("%d%d", &n, &a1); sum = a1; wz++; //s[wz].f = s[wz].son[0] = s[wz].son[1] = 0; s[wz].val = a1; root = wz; for(int i=1; i<=n-1; i++) { int dats = read(); //printf("dats=%d\n", dats); insert(dats); } printf("%d", sum); return 0; }