初识splay
这东西都没什么板子着实让我很难受啊,只能到网上抄抄补补,
记下两个用到的博客
https://blog.csdn.net/clove_unique/article/details/50630280
https://blog.csdn.net/ophunter_lcm/article/details/18157185
BZOJ 3224
复制粘贴?...
- #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 == ? 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 == ? 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 = ;
- const double eps = 1e-;
- const int inf = 0x3f3f3f3f;
- const int maxk = 1e6 + ;
- const int maxn = 1e5 + ;
- int Size, root;
- int ch[maxn<<][];
- int f[maxn<<];
- int key[maxn<<];
- int cnt[maxn<<];
- int siz[maxn<<];
- inline void clear(int x)
- { ch[x][] = ch[x][] = f[x] = cnt[x] = key[x] = siz[x] = ; }
- //判断当前点是它父节点的左儿子还是右儿子
- inline int get(int x)
- { return ch[f[x]][] == x; }
- //更新当前点size值(用于修改之后)
- inline void update(int x)
- {
- if (x) {
- siz[x] = cnt[x];
- if (ch[x][]) siz[x] += siz[ch[x][]];
- if (ch[x][]) siz[x] += siz[ch[x][]];
- }
- }
- inline void rotate(int x)
- {
- int old = f[x], oldf = f[old], which = get(x);
- ch[old][which] = ch[x][which^]; f[ch[old][which]] = old;
- f[old] = x; ch[x][which^] = old;
- f[x] = oldf;
- if (oldf)
- ch[oldf][ch[oldf][]==old] = x;
- update(old); update(x);
- }
- inline void splay(int x)
- {
- for( int fa; (fa=f[x]); rotate(x))
- if ( f[fa] )
- rotate((get(x)==get(fa) ? fa : x));
- root = x;
- }
- inline void insert(int v)
- {
- if ( root == )
- {
- Size++; ch[Size][] = ch[Size][] = f[Size] = ; key[Size] = v;
- cnt[Size] = ; siz[Size] = ; root = Size; return;
- }
- int now = root, fa = ;
- while ()
- {
- if (key[now] == v) {
- cnt[now]++;
- update(now); update(fa);
- splay(now);
- break;
- }
- fa = now;
- now = ch[now][key[now]<v];
- if (now == ) {
- Size++;
- ch[Size][] = ch[Size][] = ;
- key[Size] = v; siz[Size] = ;
- cnt[Size] = ; f[Size] = fa;
- ch[fa][key[fa]<v] = Size;
- update(fa);
- splay(Size);
- break;
- }
- }
- }
- inline int find(int v)
- {
- int ans = , now = root;
- while ()
- {
- if ( v < key[now] )
- now = ch[now][];
- else {
- ans += (ch[now][] ? siz[ch[now][]] : );
- if ( v == key[now] ) { splay(now); return ans+; }
- ans += cnt[now];
- now = ch[now][];
- }
- }
- }
- inline int findx(int x)
- {
- int now = root;
- while ()
- {
- if ( ch[now][] && x <= siz[ch[now][]] )
- now = ch[now][];
- else {
- int tmp = ( ch[now][] ? siz[ch[now][]] : ) + cnt[now];
- if ( x <= tmp )
- return key[now];
- x -= tmp;
- now = ch[now][];
- }
- }
- }
- inline int pre()
- {
- int now = ch[root][];
- while ( ch[now][] ) now = ch[now][];
- return now;
- }
- inline int next()
- {
- int now = ch[root][];
- while ( ch[now][] ) now = ch[now][];
- return now;
- }
- inline void del(int x) {
- int whatever = find(x);
- if (cnt[root]>) { cnt[root]--; return; }
- //Only One Point
- if (!ch[root][] && !ch[root][]) { clear(root); root = ; return; }
- //Only One Child
- if (!ch[root][]) {
- int oldroot = root; root = ch[root][]; f[root] = ; clear(oldroot); return;
- }
- else if (!ch[root][]) {
- int oldroot = root; root = ch[root][]; f[root] = ; clear(oldroot); return;
- }
- //Two Children
- int leftbig = pre(), oldroot = root;
- splay(leftbig);
- f[ch[oldroot][]] = root;
- ch[root][] = ch[oldroot][];
- clear(oldroot);
- update(root);
- return;
- }
- int main()
- {
- int n, opt, x;
- scanf("%d", &n);
- for (int i = ; i <= n; ++i) {
- scanf("%d%d", &opt, &x);
- switch (opt) {
- case : insert(x); break;
- case : del(x); break;
- case : printf("%d\n", find(x)); break;
- case : printf("%d\n", findx(x)); break;
- case : insert(x); printf("%d\n", key[pre()]); del(x); break;
- case : insert(x); printf("%d\n", key[next()]); del(x); break;
- }
- }
- return ;
- }
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 == ? 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 == ? 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 = ;
- const double eps = 1e-;
- const int inf = 0x3f3f3f3f;
- const int maxk = 1e6 + ;
- const int maxn = 1e5 + ;
- #define LS(n) node[(n)].ch[0]
- #define RS(n) node[(n)].ch[1]
- struct Splay {
- struct Node {
- int fa, ch[];
- bool rev;
- int val, add, maxx, size;
- void init(int _val) {
- val = maxx = _val;
- size = ;
- add = rev = ch[] = ch[] = ;
- }
- } 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 + ;
- }
- void pushDown(int n) {
- if (n == ) 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 = ;
- }
- if (node[n].rev) {
- if (LS(n)) node[LS(n)].rev ^= ;
- if (RS(n)) node[RS(n)].rev ^= ;
- swap(LS(n), RS(n));
- node[n].rev = ;
- }
- }
- ///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 == ) 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 + ;
- u = RS(u);
- }
- pushDown(u);
- }
- return u;
- }
- int query(int L, int R) {
- int u = select(L - ), v = select(R + );
- splay(u, ); splay(v, u); ///通过旋转操作把询问的区间聚集到根的右子树的左子树下
- return node[LS(v)].maxx;
- }
- void pushUpdate(int L, int R, int val) {
- int u = select(L - ), v = select(R + );
- splay(u, ); 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 - ), v = select(R + );
- splay(u, ); splay(v, u);
- node[LS(v)].rev ^= ;
- }
- ///返回子树的根节点
- int build(int L, int R) {
- if (L > R) return ;
- if (L == R) return L;
- int mid = (L + R) >> ;
- int r_L, r_R;
- LS(mid) = r_L = build(L, mid - );
- RS(mid) = r_R = build(mid + , R);
- node[r_L].fa = node[r_R].fa = mid;
- pushUp(mid);
- return mid;
- }
- ///按照数组的下标顺序作为建树依据
- ///而不是按照数组内的元素大小做依据
- void init(int n) {
- ///0号节点最大值和值都是负无穷
- node[].init(-inf); node[].size = ;
- node[].init(-inf);
- node[n + ].init(-inf);
- for (int i = ; i <= n + ; ++i)
- node[i].init();
- root = build(, n + );
- node[root].fa = ;
- node[].fa = ;
- LS() = root;
- }
- } splay_tree;
- int main() {
- int n, m;
- scanf("%d%d", &n, &m);
- splay_tree.init(n);
- for (int i = ; i < m; ++i) {
- int op, l, r, v;
- scanf("%d", &op);
- if (op == ) {
- scanf("%d%d%d", &l, &r, &v);
- splay_tree.pushUpdate(l, r, v);
- }
- else if (op == ) {
- 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 ;
- }
初识splay的更多相关文章
- [洛谷P3391] 文艺平衡树 (Splay模板)
初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...
- BZOJ 3223: Tyvj 1729 文艺平衡树
3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3628 Solved: 2052[Submit][Sta ...
- Android动画效果之初识Property Animation(属性动画)
前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)
一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...
- 初识IOS,Label控件的应用。
初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...
- UI篇(初识君面)
我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...
- Python导出Excel为Lua/Json/Xml实例教程(一):初识Python
Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...
- BZOJ 1251: 序列终结者 [splay]
1251: 序列终结者 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3778 Solved: 1583[Submit][Status][Discu ...
随机推荐
- JAVA数据结构之哈希表
Hash表简介: Hash表是基于数组的,优点是提供快速的插入和查找的操作,编程实现相对容易,缺点是一旦创建就不好扩展,当hash表被基本填满的时候,性能下降非常严重(发生聚集引起的性能的下降),而且 ...
- if else 和 swith效率比较
读大话设计模式,开头的毛病代码用if else实现了计算器,说计算机做了三次无用功,优化后是用switch,那么switch为什么比if else效率高呢, 百度找了几个说是底层算法不一样,找了一个比 ...
- 固定定位fixed,绝对定位absolute,相对定位relative;以及overflow
固定定位position:fixed /*固定定位 1.定位属性值:fixed 2.在页面中不再占位(浮起来了) 3.一旦定位后,定位的布局方位 top.bottom.left.right都能参与布局 ...
- JS 基本的介绍
JS中的注释 HTML的注释:<!—注释内容--> CSS注释:/* 注释 */ JavaScript的注释:// 或 /* 多行注释 */ 变量 1.变量的概念 变量是变化 ...
- fastjson 过滤不需要序列化的属性
JSON JSON英文全称为JavaScriptObject Natation,采用key:value键值对的方式存贮数据,与xml格式相比,JSON是一种轻量级的数据交换格式:不要被JavaScri ...
- STM32F103 Feature
- <Python基础>集合的基本操作
#小知识点:返回对象的内存地址 i,j = 1,2 print(id(i),id(j)) #集合的基本操作, #相当于没有键值对的字典,里面的元素是无序且不重复的 #一般写法 s = set({1,2 ...
- Win10命令提示符git log中文乱码的解决方案
在系统环境变量中新建一个名为LESSCHARSET的变量 其值为utf-8 新建完毕后应用,git log就不会出现乱码的问题了^_^ 参考博文:git- win10 cmd git log 中文乱码 ...
- 连接RDS数据库
- 单体内置对象——Global对象
单体内置对象的定义:由ECMAScript实现提供的.不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前已经存在了.意思就是说:开发人员不必显式地实例化内置对象,因为他们已经实例化了. ...