初识splay
这东西都没什么板子着实让我很难受啊,只能到网上抄抄补补,
记下两个用到的博客
https://blog.csdn.net/clove_unique/article/details/50630280
https://blog.csdn.net/ophunter_lcm/article/details/18157185
BZOJ 3224
复制粘贴?...
1 #include <iostream> 2 #include <string.h> 3 #include <cstdio> 4 #include <vector> 5 #include <queue> 6 #include <math.h> 7 #include <string> 8 #include <algorithm> 9 #include <time.h> 10 11 #define SIGMA_SIZE 26 12 #define lson rt<<1 13 #define rson rt<<1|1 14 #define lowbit(x) (x&-x) 15 #define foe(i, a, b) for(int i=a; i<=b; i++) 16 #define fo(i, a, b) for(int i=a; i<b; i++); 17 #pragma warning ( disable : 4996 ) 18 19 using namespace std; 20 typedef long long LL; 21 inline LL LMax(LL a, LL b) { return a>b ? a : b; } 22 inline LL LMin(LL a, LL b) { return a>b ? b : a; } 23 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); } 24 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; } //a*b = gcd*lcm 25 inline int Max(int a, int b) { return a>b ? a : b; } 26 inline int Min(int a, int b) { return a>b ? b : a; } 27 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } 28 inline int lcm(int a, int b) { return a / gcd(a, b)*b; } //a*b = gcd*lcm 29 const LL INF = 0x3f3f3f3f3f3f3f3f; 30 const LL mod = 1000000007; 31 const double eps = 1e-8; 32 const int inf = 0x3f3f3f3f; 33 const int maxk = 1e6 + 5; 34 const int maxn = 1e5 + 5; 35 36 int Size, root; 37 int ch[maxn<<2][2]; 38 int f[maxn<<2]; 39 int key[maxn<<2]; 40 int cnt[maxn<<2]; 41 int siz[maxn<<2]; 42 43 inline void clear(int x) 44 { ch[x][0] = ch[x][1] = f[x] = cnt[x] = key[x] = siz[x] = 0; } 45 46 //判断当前点是它父节点的左儿子还是右儿子 47 inline int get(int x) 48 { return ch[f[x]][1] == x; } 49 50 //更新当前点size值(用于修改之后) 51 inline void update(int x) 52 { 53 if (x) { 54 siz[x] = cnt[x]; 55 if (ch[x][0]) siz[x] += siz[ch[x][0]]; 56 if (ch[x][1]) siz[x] += siz[ch[x][1]]; 57 } 58 } 59 60 inline void rotate(int x) 61 { 62 int old = f[x], oldf = f[old], which = get(x); 63 ch[old][which] = ch[x][which^1]; f[ch[old][which]] = old; 64 f[old] = x; ch[x][which^1] = old; 65 f[x] = oldf; 66 if (oldf) 67 ch[oldf][ch[oldf][1]==old] = x; 68 update(old); update(x); 69 } 70 71 inline void splay(int x) 72 { 73 for( int fa; (fa=f[x]); rotate(x)) 74 if ( f[fa] ) 75 rotate((get(x)==get(fa) ? fa : x)); 76 root = x; 77 } 78 79 inline void insert(int v) 80 { 81 if ( root == 0 ) 82 { 83 Size++; ch[Size][0] = ch[Size][1] = f[Size] = 0; key[Size] = v; 84 cnt[Size] = 1; siz[Size] = 1; root = Size; return; 85 } 86 87 int now = root, fa = 0; 88 while (1) 89 { 90 if (key[now] == v) { 91 cnt[now]++; 92 update(now); update(fa); 93 splay(now); 94 break; 95 } 96 fa = now; 97 now = ch[now][key[now]<v]; 98 if (now == 0) { 99 Size++; 100 ch[Size][0] = ch[Size][1] = 0; 101 key[Size] = v; siz[Size] = 1; 102 cnt[Size] = 1; f[Size] = fa; 103 ch[fa][key[fa]<v] = Size; 104 update(fa); 105 splay(Size); 106 break; 107 } 108 } 109 } 110 111 inline int find(int v) 112 { 113 int ans = 0, now = root; 114 while (1) 115 { 116 if ( v < key[now] ) 117 now = ch[now][0]; 118 else { 119 ans += (ch[now][0] ? siz[ch[now][0]] : 0); 120 if ( v == key[now] ) { splay(now); return ans+1; } 121 122 ans += cnt[now]; 123 now = ch[now][1]; 124 } 125 } 126 } 127 128 inline int findx(int x) 129 { 130 int now = root; 131 while (1) 132 { 133 if ( ch[now][0] && x <= siz[ch[now][0]] ) 134 now = ch[now][0]; 135 else { 136 int tmp = ( ch[now][0] ? siz[ch[now][0]] : 0) + cnt[now]; 137 138 if ( x <= tmp ) 139 return key[now]; 140 x -= tmp; 141 now = ch[now][1]; 142 } 143 } 144 } 145 146 inline int pre() 147 { 148 int now = ch[root][0]; 149 while ( ch[now][1] ) now = ch[now][1]; 150 return now; 151 } 152 153 inline int next() 154 { 155 int now = ch[root][1]; 156 while ( ch[now][0] ) now = ch[now][0]; 157 return now; 158 } 159 160 161 inline void del(int x) { 162 int whatever = find(x); 163 if (cnt[root]>1) { cnt[root]--; return; } 164 //Only One Point 165 if (!ch[root][0] && !ch[root][1]) { clear(root); root = 0; return; } 166 //Only One Child 167 if (!ch[root][0]) { 168 int oldroot = root; root = ch[root][1]; f[root] = 0; clear(oldroot); return; 169 } 170 else if (!ch[root][1]) { 171 int oldroot = root; root = ch[root][0]; f[root] = 0; clear(oldroot); return; 172 } 173 //Two Children 174 int leftbig = pre(), oldroot = root; 175 splay(leftbig); 176 f[ch[oldroot][1]] = root; 177 ch[root][1] = ch[oldroot][1]; 178 clear(oldroot); 179 update(root); 180 return; 181 } 182 183 int main() 184 { 185 int n, opt, x; 186 scanf("%d", &n); 187 for (int i = 1; i <= n; ++i) { 188 scanf("%d%d", &opt, &x); 189 switch (opt) { 190 case 1: insert(x); break; 191 case 2: del(x); break; 192 case 3: printf("%d\n", find(x)); break; 193 case 4: printf("%d\n", findx(x)); break; 194 case 5: insert(x); printf("%d\n", key[pre()]); del(x); break; 195 case 6: insert(x); printf("%d\n", key[next()]); del(x); break; 196 } 197 } 198 199 200 return 0; 201 }
BZOJ 1251(区间翻转和区间增加一个值V)
这份代码比较清晰易懂
https://blog.csdn.net/whai362/article/details/47298133(加了一些注释
/*bzoj 1251 序列终结者 题意: 给定一个长度为N的序列,每个序列的元素是一个整数。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V; 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1; 3. 求[L,R]这个区间中的最大值; 最开始所有元素都是0。 限制: N <= 50000, M <= 100000 思路: 伸展树 关键点: 1. 伸展树为左小右大的二叉树,所以旋转操作不会影响树的性质 2. 区间操作为: int u = select(L - 1), v = select(R + 1); splay(u, 0); splay(v, u); //通过旋转操作把询问的区间聚集到根的右子树的左子树下 因为伸展树为左小右大的二叉树,旋转操作后的所以对于闭区间[L, R]之间的所有元素都聚集在根的右子树的左子树下 因为闭区间[L, R], 1) 所以每次都要查开区间(L - 1, R + 1), 2) 所以伸展树元素1对应的标号为2, 3) 所以node[0]对应空节点,node[1]对应比所以元素标号都小的点,node[2 ~ n + 1]对应元素1 ~ n,node[n + 2]对应比所有元素标号都打的点,其中node[0], node[1], node[n + 2]都是虚节点,不代表任何元素。 */ #include <iostream> #include <string.h> #include <cstdio> #include <vector> #include <queue> #include <math.h> #include <string> #include <algorithm> #include <time.h> #define SIGMA_SIZE 26 #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) (x&-x) #define foe(i, a, b) for(int i=a; i<=b; i++) #define fo(i, a, b) for(int i=a; i<b; i++); #pragma warning ( disable : 4996 ) using namespace std; typedef long long LL; inline LL LMax(LL a, LL b) { return a>b ? a : b; } inline LL LMin(LL a, LL b) { return a>b ? b : a; } inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); } inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; } //a*b = gcd*lcm inline int Max(int a, int b) { return a>b ? a : b; } inline int Min(int a, int b) { return a>b ? b : a; } inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } inline int lcm(int a, int b) { return a / gcd(a, b)*b; } //a*b = gcd*lcm const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = 1000000007; const double eps = 1e-8; const int inf = 0x3f3f3f3f; const int maxk = 1e6 + 5; const int maxn = 1e5 + 5; #define LS(n) node[(n)].ch[0] #define RS(n) node[(n)].ch[1] struct Splay { struct Node { int fa, ch[2]; bool rev; int val, add, maxx, size; void init(int _val) { val = maxx = _val; size = 1; add = rev = ch[0] = ch[1] = 0; } } node[maxn]; int root; ///相当于线段树的pushup和pushdown void pushUp(int n) { node[n].maxx = Max(node[n].val, Max(node[LS(n)].maxx, node[RS(n)].maxx)); node[n].size = node[LS(n)].size + node[RS(n)].size + 1; } void pushDown(int n) { if (n == 0) return; if (node[n].add) { if (LS(n)) { node[LS(n)].val += node[n].add; node[LS(n)].maxx += node[n].add; node[LS(n)].add += node[n].add; } if (RS(n)) { node[RS(n)].val += node[n].add; node[RS(n)].maxx += node[n].add; node[RS(n)].add += node[n].add; } node[n].add = 0; } if (node[n].rev) { if (LS(n)) node[LS(n)].rev ^= 1; if (RS(n)) node[RS(n)].rev ^= 1; swap(LS(n), RS(n)); node[n].rev = 0; } } ///kind = 0为左旋 ///kind = 1为右旋 void rotate(int n, bool kind) { int fn = node[n].fa; int ffn = node[fn].fa; node[fn].ch[!kind] = node[n].ch[kind]; node[node[n].ch[kind]].fa = fn; node[n].ch[kind] = fn; node[fn].fa = n; node[ffn].ch[RS(ffn) == fn] = n; node[n].fa = ffn; pushUp(fn); } void splay(int n, int goal) { while (node[n].fa != goal) { int fn = node[n].fa; int ffn = node[fn].fa; //三连pushDown pushDown(ffn); pushDown(fn); pushDown(n); bool rotate_n = (LS(fn) == n); bool rotate_fn = (LS(ffn) == fn); if (ffn == goal) rotate(n, rotate_n); else { if (rotate_n == rotate_fn) rotate(fn, rotate_fn); else rotate(n, rotate_n); rotate(n, rotate_fn); } } pushUp(n); if (goal == 0) root = n; } ///通过数组中的位置找在树中的位置 int select(int pos) { int u = root; pushDown(u); while (node[LS(u)].size != pos) { if (pos < node[LS(u)].size) u = LS(u); else { pos -= node[LS(u)].size + 1; u = RS(u); } pushDown(u); } return u; } int query(int L, int R) { int u = select(L - 1), v = select(R + 1); splay(u, 0); splay(v, u); ///通过旋转操作把询问的区间聚集到根的右子树的左子树下 return node[LS(v)].maxx; } void pushUpdate(int L, int R, int val) { int u = select(L - 1), v = select(R + 1); splay(u, 0); splay(v, u); node[LS(v)].val += val; node[LS(v)].maxx += val; node[LS(v)].add += val; } void reverse(int L, int R) { int u = select(L - 1), v = select(R + 1); splay(u, 0); splay(v, u); node[LS(v)].rev ^= 1; } ///返回子树的根节点 int build(int L, int R) { if (L > R) return 0; if (L == R) return L; int mid = (L + R) >> 1; int r_L, r_R; LS(mid) = r_L = build(L, mid - 1); RS(mid) = r_R = build(mid + 1, R); node[r_L].fa = node[r_R].fa = mid; pushUp(mid); return mid; } ///按照数组的下标顺序作为建树依据 ///而不是按照数组内的元素大小做依据 void init(int n) { ///0号节点最大值和值都是负无穷 node[0].init(-inf); node[0].size = 0; node[1].init(-inf); node[n + 2].init(-inf); for (int i = 2; i <= n + 1; ++i) node[i].init(0); root = build(1, n + 2); node[root].fa = 0; node[0].fa = 0; LS(0) = root; } } splay_tree; int main() { int n, m; scanf("%d%d", &n, &m); splay_tree.init(n); for (int i = 0; i < m; ++i) { int op, l, r, v; scanf("%d", &op); if (op == 1) { scanf("%d%d%d", &l, &r, &v); splay_tree.pushUpdate(l, r, v); } else if (op == 2) { scanf("%d%d", &l, &r); splay_tree.reverse(l, r); } else { scanf("%d%d", &l, &r); printf("%d\n", splay_tree.query(l, r)); } } return 0; }
什么时候能够不再这么懒惰