Splay树学习
首先给出一论文讲的很好:
http://www.docin.com/p-63165342.html
http://www.docin.com/p-62465596.html
然后给出模板胡浩大神的模板:http://www.notonlysuccess.com/index.php/splay-tree/
好像胡浩大神的没有给注释,然后给出cxlove的,给出了详细的注释:
http://blog.csdn.net/acm_cxlove/article/details/7790895
然后给出模板题目:
题意:中文..
思路:
每输入一个值,我们就更新splay树,然后找他的左子树中最靠右的,右子树中最靠左的那肯定和他的距离差值是最小的。然后求和即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x) (x) << 1
#define R(x) (x) << 1 | 1
#define MID(l, r) (l + r) >> 1
#define Min(x, y) (x) < (y) ? (x) : (y)
#define Max(x, y) (x) < (y) ? (y) : (x)
#define E(x) (1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x) printf("%I64d\n", x)
#define lowbit(x) (x)&(-x)
#define Read() freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout); #define M 137
#define N 32777 using namespace std; const int inf = 0x7f7f7f7f;
const ll mod = ; struct SplayTree
{
int chd[N][],pre[N],key[N];
int root,tot;
//生成新节点
void newNode(int &r,int fa,int k)
{
r = ++tot;
pre[r] = fa;
key[r] = k;
chd[r][] = chd[r][] = ;
}
//旋转
void Rotate(int x,int kd)
{
int y = pre[x];
chd[y][!kd] = chd[x][kd];
pre[chd[x][kd]] = y; if (pre[y] != ) chd[pre[y]][chd[pre[y]][] == y] = x;
pre[x] = pre[y];
pre[y] = x;
chd[x][kd] = y;
}
//
void Splay(int r,int g)
{
while (pre[r] != g)
{
if (pre[pre[r]] == g) Rotate(r,chd[pre[r]][] == r);
else
{
int y = pre[r];
int kd = chd[pre[y]][] == y;
if (chd[pre[r]][kd] == r)
{
Rotate(r,!kd);
Rotate(r,kd);
}
else
{
Rotate(y,kd);
Rotate(r,kd);
}
}
}
if (g == ) root = r;
}
//插入
int insert(int k)
{
int r = root;
while (chd[r][key[r] < k])
{
if (key[r] == k)
{
Splay(r,);
return ;
}
r = chd[r][key[r] < k];
}
newNode(chd[r][key[r]< k],r,k);
Splay(chd[r][key[r] < k],);
return ;
}
int get_next(int x)
{
int rg = chd[x][];
if (rg == ) return inf;
while (chd[rg][]) rg = chd[rg][];
return key[rg] - key[x];
}
int get_pre(int x)
{
int lt = chd[x][];
if (lt == ) return inf;
while (chd[lt][]) lt = chd[lt][];
return key[x] - key[lt];
}
}spt; int n;
int main()
{
// Read();
int x;
while (~scanf("%d",&n))
{
spt.tot = spt.root = ;
int ans = ;
for (int i = ; i <= n; ++i)
{
scanf("%d",&x);
// cout<< ">>>>" << x << endl;
if (i == )
{
ans += x;
spt.newNode(spt.root,,x);
}
else
{
if (spt.insert(x) == ) continue;
int a = spt.get_next(spt.root);
int b = spt.get_pre(spt.root);
ans += min(a,b);
}
// cout << ans << endl;
}
printf("%d\n",ans);
}
return ;
}
线段树可解决的问题,Splay解决:
pku 3468 A Simple Problem with Integers
成段更新,区间询问
第二个论文里面有提到如何通过Splay的操作来实现。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x) (x) << 1
#define R(x) (x) << 1 | 1
#define MID(l, r) (l + r) >> 1
#define Min(x, y) (x) < (y) ? (x) : (y)
#define Max(x, y) (x) < (y) ? (y) : (x)
#define E(x) (1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x) printf("%I64d\n", x)
#define lowbit(x) (x)&(-x)
#define keyTree (chd[chd[root][1]][0])
#define Read() freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout); #define M 137
#define N 200007 using namespace std; const int inf = 0x7f7f7f7f;
const int mod = ; struct SpayTree
{
public:
int sz[N];
int ss[N],que[N];
int chd[N][],pre[N];
int top1,top2,root; inline void Rotate(int x,int kd)
{
int y = pre[x];
pushdown(y);
pushdown(x);
chd[y][!kd] = chd[x][kd];
pre[chd[x][kd]] = y;
pre[x] = pre[y]; if (pre[x]) chd[pre[y]][chd[pre[y]][] == y] = x;
chd[x][kd] = y;
pre[y] = x;
pushup(y);
}
inline void Splay(int x,int goal)
{
pushdown(x);
while (pre[x] != goal)
{
if (pre[pre[x]] == goal)
{
Rotate(x,chd[pre[x]][] == x);
}
else
{
int y = pre[x],z = pre[y];
int kd = (chd[z][] == y);
if (chd[y][kd] == x)
{
Rotate(x,!kd); Rotate(x,kd);
}
else
{
Rotate(y,kd); Rotate(x,kd);
}
}
}
pushup(x);
if (goal == ) root = x;
}
inline void RotateTo(int k,int goal)
{
int x = root;
pushdown(x);
while (sz[chd[x][]] != k)
{
if (k < sz[chd[x][]])
{
x = chd[x][];
}
else
{
k -= (sz[chd[x][]] + );
x = chd[x][];
}
pushdown(x);
}
Splay(x,goal);
}
inline void erase(int x)
{
int fa = pre[x];
int head = , tail = ;
for (que[tail++] = x; head < tail; ++head)
{
ss[top2++] = que[head];
if (chd[que[head]][]) que[tail++] = chd[que[head]][];
if (chd[que[head]][]) que[tail++] = chd[que[head]][];
}
chd[fa][chd[fa][] == x] = ;
pushup(fa);
} /* 以上基本为固定模板 */ inline void pushup(int rt)
{
sz[rt] = sz[chd[rt][]] + sz[chd[rt][]] + ;
sum[rt] = add[rt] + val[rt] + sum[chd[rt][]] + sum[chd[rt][]];
}
inline void pushdown(int rt)
{
if (add[rt])
{
val[rt] += add[rt];
add[chd[rt][]] += add[rt];
add[chd[rt][]] += add[rt];
sum[chd[rt][]] += (ll)sz[chd[rt][]]*add[rt];
sum[chd[rt][]] += (ll)sz[chd[rt][]]*add[rt];
add[rt] = ;
}
}
inline void newNode(int &x,int c)
{
if (top2) x = ss[--top2];
else x = ++top1;
chd[x][] = chd[x][] = pre[x] = ;
sz[x] = ;
val[x] = sum[x] = c;
add[x] = ;
}
inline void makeTree(int &x,int l,int r, int f)
{
if (l > r) return ;
int m = (l + r)>>;
newNode(x,num[m]);
makeTree(chd[x][],l,m - ,x);
makeTree(chd[x][],m + ,r,x);
pre[x] = f;
pushup(x);
}
inline void init(int n)
{
chd[][] = chd[][] = pre[] = ;
add[] = sum[] = sz[] = ; root = top1 = ;
newNode(root,-);
// pre[root] = 0;
newNode(chd[root][],-);
pre[top1] = root;
sz[root] = ; for (int i = ; i < n; ++i) scanf("%d",&num[i]);
makeTree(keyTree,,n - ,chd[root][]);
pushup(chd[root][]); pushup(root);
} inline void update()
{
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
RotateTo(l - ,);
RotateTo(r + ,root);
add[keyTree] += c;
sum[keyTree] += (ll)c*sz[keyTree];
}
inline void query()
{
int l,r;
scanf("%d%d",&l,&r);
RotateTo(l - ,);
RotateTo(r + ,root);
printf("%I64d\n",sum[keyTree]);
} ll sum[N];
int add[N];
int val[N];
int num[N]; }spt; int main()
{
// Read();
int n,m;
scanf("%d%d",&n,&m);
spt.init(n);
while (m--)
{
char op[];
scanf("%s",op);
if (op[] == 'Q') spt.query();
else spt.update();
}
return ;
}
题意:
给你n个数,然后每次找到第i大的数,放到第i个位置,然后将第i大的数的位置 - 1到i这个区间逆置,求第i大的数的位置
思路:
直接Splay模拟,然后构造两个边界点,旋转达到求逆的效果。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define L(x) (x) << 1
#define R(x) (x) << 1 | 1
#define MID(l, r) (l + r) >> 1
#define Min(x, y) (x) < (y) ? (x) : (y)
#define Max(x, y) (x) < (y) ? (y) : (x)
#define E(x) (1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x) printf("%I64d\n", x)
#define lowbit(x) (x)&(-x)
#define Read() freopen("data.in", "r", stdin)
#define Write() freopen("d.out", "w", stdout)
#define ll unsigned long long
#define keyTree (chd[chd[root][1]][0]) #define M 100007
#define N 100017 using namespace std; const int inf = 0x7f7f7f7f;
const int mod = ; int n;
struct node
{
int val;
int idx;
}nd[N]; int cmp(node a,node b)
{
return a.val < b.val;
}
class SplayTree
{
public: int son[N][],pre[N];
int rt,top;
int sz[N],rev[N]; void Link(int x,int y,int c)
{
pre[x] = y; son[y][c] = x;
}
void Rotate(int x,int c)
{
int y = pre[x];
pushdown(y); pushdown(x);
Link(x , pre[y], son[pre[y]][] == y);
Link(son[x][!c],y,c);
Link(y,x,!c);
pushup(y);
}
void Splay(int x,int g)
{
for (pushdown(x); pre[x] != g;)
{
int y = pre[x],cx = son[y][] == x,cy = son[pre[y]][] == y;
if (pre[y] == g) Rotate(x,cx);
else
{
if (cx == cy) Rotate(y,cy);
else Rotate(x,cx);
Rotate(x,cy);
}
}
pushup(x);
if (g == ) rt = x;
}
int RotateTo(int k,int g)
{
int x = rt;
pushdown(x);
while (sz[son[x][]] != k)
{
if (sz[son[x][]] > k) x = son[x][];
else k -= sz[son[x][]] + , x = son[x][];
pushdown(x);
}
Splay(x,g);
return x;
}
void NewNode(int y ,int &x,int k)
{
x = ++top;
pre[x] = y; sz[x] = ; nd[k].idx = x;
rev[x] = son[x][] = son[x][] = ;
}
void pushup(int x)
{
sz[x] = sz[son[x][]] + sz[son[x][]] + ;
}
void Reverse(int x)
{
rev[x] ^= ;
swap(son[x][],son[x][]);
}
void pushdown(int x)
{
if (rev[x])
{
Reverse(son[x][]);
Reverse(son[x][]);
rev[x] = ;
}
}
void makeTree(int l,int r,int &x,int y)
{
if (l > r) return;
int m = (l + r)>>;
NewNode(y,x,m);
makeTree(l,m - ,son[x][],x);
makeTree(m + ,r,son[x][],x);
pushup(x);
}
void init()
{
for (int i = ; i <= n; ++i)
{
scanf("%d",&nd[i].val);
}
NewNode(top = ,rt,);
NewNode(rt,son[rt][],);
makeTree(,n,son[][],);
Splay(,);
}
void solve()
{
for (int i = ; i <= n; ++i)
{
int idx = nd[i].idx;
Splay(idx, );
int ans = sz[son[rt][]];
RotateTo(i - ,);
int y = RotateTo(ans + ,rt);
Reverse(son[y][]);
printf("%d%c",ans,i < n ? ' ': '\n');
}
}
}spt; int main()
{
// Read();
while (~scanf("%d",&n))
{
if (!n) break;
spt.init();
stable_sort(nd + ,nd + + n, cmp);
// for (int i = 1; i <= n; ++i) printf("%d %d\n",nd[i].val,nd[i].idx);
spt.solve();
}
return ;
}
题意:
给你一个序列1...n 有三种操作:
1. Top x :Take person x to the front of the queue
2. Query x: calculate the current position of person x
3. Rank x: calculate the current person at position x
输出每次的询问
思路:
首先我们关键是点的离散化,然后建立树上的边到数组的点的映射,然后利用Splay模拟这个过程就行。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define L(x) (x) << 1
#define R(x) (x) << 1 | 1
#define MID(l, r) (l + r) >> 1
#define Min(x, y) (x) < (y) ? (x) : (y)
#define Max(x, y) (x) < (y) ? (y) : (x)
#define E(x) (1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x) printf("%I64d\n", x)
#define lowbit(x) (x)&(-x)
#define Read() freopen("data.in", "r", stdin)
#define Write() freopen("d.out", "w", stdout)
#define ll unsigned long long
#define keyTree (chd[chd[root][1]][0]) #define M 100007
#define N 300017 using namespace std; const int inf = 0x7f7f7f7f;
const int mod = ; int p[N],a[N];
char op[N][];
int s[N],e[N];
int tot;
int n,m; class SplayTree
{
public:
int sz[N];
int key[N],nd[N];
int son[N][],pre[N];
int num[N];
int rt,top; inline void Link(int x,int y,int c)
{
pre[x] = y; son[y][c] = x;
}
inline void Rotate(int x,int c)
{
int y = pre[x];
Link(x,pre[y],son[pre[y]][] == y);
Link(son[x][!c],y,c);
Link(y,x,!c);
pushup(y);
}
inline void Splay(int x,int g)
{
for (; pre[x] != g;)
{
int y = pre[x], cx = son[y][] == x, cy = son[pre[y]][] == y;
if (pre[y] == g) Rotate(x,cx);
else
{
if (cx == cy) Rotate(y,cy);
else Rotate(x,cx);
Rotate(x,cy);
}
}
pushup(x);
if (g == ) rt = x;
}
inline void pushup(int x)
{
sz[x] = sz[son[x][]] + sz[son[x][]] + num[x];
}
inline void NewNode(int &x,int y,int c)
{
x = ++top; pre[x] = y;
son[x][] = son[x][] = ;
sz[x] = num[x] = e[c] - s[c] + ;
key[x] = c; nd[c] = x;//将树上的点与数组的中的建立映射
}
inline void makeTree(int l,int r,int &x,int f)
{
if (l > r) return ;
int m = (l + r)>>;
NewNode(x,f,m);
makeTree(l,m - ,son[x][],x);
makeTree(m + ,r,son[x][],x);
pushup(x);
}
inline void init()
{
son[][] = son[][] = pre[] = ;
sz[] = ; num[] = ; top = ;
key[] = nd[] = ;
makeTree(,tot - ,rt,);
}
inline void Query(int k)
{
int tx = lower_bound(s, s + tot, k) - s;
int x = nd[tx];
Splay(x,);
printf("%d\n",sz[son[rt][]] + );
}
inline int Find(int k,int rt)//查找第k大
{
int t = sz[son[rt][]];
if (k <= t) return Find(k,son[rt][]);
else if (k <= t + num[rt]) return s[key[rt]] + (k - t) - ;
else return Find(k - (t + num[rt]),son[rt][]);
}
inline int get_min(int x)
{
while (son[x][]) x = son[x][];
return x;
}
inline void Del_R()
{
if (!son[rt][] || !son[rt][])
{
rt = son[rt][] + son[rt][];
pre[rt] = ;
}
else
{
int k = get_min(son[rt][]);//找到右子树中最小的点
Splay(k,rt);//旋转到根节点下边这样保证根节点达到右子树的左子树为空
//合并将根节点删除
son[son[rt][]][] = son[rt][];
rt = son[rt][];
pre[son[rt][]] = rt;
pre[rt] = ;
pushup(rt);
}
}
//不断的往左插入
inline void Insert(int &x,int k,int f)
{
if (x == )
{
NewNode(x,f,k);
return ;
}
Insert(son[x][],k,x);
pushup(x);
}
inline void Top(int k)
{
int tx = lower_bound(s, s + tot, k) - s;
int x = nd[tx];
Splay(x,);
Del_R();
Insert(rt,tx,);
Splay(top,);//这里如果不加会TLE致死。。
}
inline void solve()
{
for (int i = ; i < m; ++i)
{
if (op[i][] == 'T') Top(a[i]);
else if (op[i][] == 'Q') Query(a[i]);
else printf("%d\n",Find(a[i],rt));
}
}
}spt; int main()
{
// Read();
int T,cas = ;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
//对我们需要询问或者处理的点进行离散化,将不变的区间进行缩点离散
int k = ;
p[k++] = ;
for (int i = ; i < m; ++i)
{
scanf("%s%d",op[i],&a[i]);
if (op[i][] == 'Q' || op[i][] == 'T')
{
p[k++] = a[i];
}
}
p[k++] = n; sort(p,p + k);
tot = ;
s[tot] = p[];
e[tot++] = p[]; for (int i = ; i < k; ++i)
{
if (p[i] != p[i - ])
{
if (p[i - ] + < p[i])//将区间缩点
{
s[tot] = p[i - ] + ;
e[tot++] = p[i] - ;
}
s[tot] = p[i];
e[tot++] = p[i];
}
}
printf("Case %d:\n",cas++);
spt.init();
spt.solve();
}
return ;
}
Splay树学习的更多相关文章
- 文艺平衡Splay树学习笔记(2)
本blog会讲一些简单的Splay的应用,包括但不局限于 1. Splay 维护数组下标,支持区间reserve操作,解决区间问题 2. Splay 的启发式合并(按元素多少合并) 3. 线段树+Sp ...
- 暑假学习日记:Splay树
从昨天开始我就想学这个伸展树了,今天花了一个上午2个多小时加下午2个多小时,学习了一下伸展树(Splay树),学习的时候主要是看别人博客啦~发现下面这个博客挺不错的http://zakir.is-pr ...
- Splay树再学习
队友最近可能在学Splay,然后让我敲下HDU1754的题,其实是很裸的一个线段树,不过用下Splay也无妨,他说他双旋超时,单旋过了,所以我就敲来看下.但是之前写的那个Splay越发的觉得不能看,所 ...
- BST,Splay平衡树学习笔记
BST,Splay平衡树学习笔记 1.二叉查找树BST BST是一种二叉树形结构,其特点就在于:每一个非叶子结点的值都大于他的左子树中的任意一个值,并都小于他的右子树中的任意一个值. 2.BST的用处 ...
- Splay树-Codevs 1296 营业额统计
Codevs 1296 营业额统计 题目描述 Description Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司 ...
- ZOJ3765 Lights Splay树
非常裸的一棵Splay树,需要询问的是区间gcd,但是区间上每个数分成了两种状态,做的时候分别存在val[2]的数组里就好.区间gcd的时候基本上不支持区间的操作了吧..不然你一个区间里加一个数gcd ...
- 1439. Battle with You-Know-Who(splay树)
1439 路漫漫其修远兮~ 手抄一枚splay树 长长的模版.. 关于spaly树的讲解 网上很多随手贴一篇 貌似这题可以用什么bst啦 堆啦 平衡树啦 等等 这些本质都是有共同点的 查找.删除特 ...
- 伸展树(Splay树)的简要操作
伸展树(splay树),是二叉排序树的一种.[两个月之前写过,今天突然想写个博客...] 伸展树和一般的二叉排序树不同的是,在每次执行完插入.查询.删除等操作后,都会自动平衡这棵树.(说是自动,也就是 ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
随机推荐
- Unity3D笔记三 物理引擎
一.物理引擎 1.物理引擎就是模拟真实世界中物体碰撞.跌落等反应,通过Ballance.愤怒的小鸟来理解什么是物理引擎.Unity的物理引擎使用的是NviDIA的PhysX.2.选中一个游戏对象,主菜 ...
- SMGP关键代码
从网上下载java的API就可以开发了我们需要修改的类是: import java.io.IOException; import cn.com.zjtelecom.smgp.Client; impor ...
- Apache的配置详解,最好的Apache配置文档
http://blog.csdn.net/apple_llb/article/details/50253889 Apache的配置由httpd.conf文件配置,因此下面的配置指令都是在httpd.c ...
- C# tostring 格式化输出
C 货币 2.5.ToString("C") ¥2.50 D 十进制数 25.ToString("D5") 00025 E 科学型 25000.ToString ...
- AIX安装CDE,CDE服务开启和关闭
1.将AIX的光盘镜像通过ftp工具上传至/mnt目录下,如下图: 2.创建目录/media作为默认的AIX光盘挂载区 # mkdir /media 3.将AIX的第一张光盘挂载到/media目录下: ...
- 过千万、亿条数据的mysql表更新 mysql 线程状态
分段更新 UPDATE question SET `status`=1 WHERE status!=1 LIMIT 3000;UPDATE answer SET `status`=1 WHERE st ...
- OpenPGP协议的一个JavaScript实现:OpenPGP.js
OpenPGP.js 是OpenPGP协议的一个Javascript实现. 基于 JavaScript的OpenPGP实现方便用户可以直接在浏览器中加密和解密Web邮件,不需要专门的邮件客户端.
- Linux下批量管理工具pssh使用记录
pssh是一款开源的软件,使用python实现,用于批量ssh操作大批量机器:pssh是一个可以在多台服务器上执行命令的工具,同时支持拷贝文件,是同类工具中很出色的:比起for循环的做法,我更推荐使用 ...
- PHP关于函数的参数问题
可能是自己以前写程序太规范了,今天发现个PHP函数参数个数的问题,定义的函数有三个参数,但是使用函数的时候竟然传了四个参数,更意外的是程序运行没有错误,甚至没有警告.于是依靠搜索引擎和PHP文档仔细查 ...
- 人人网张铁安:Feed系统架构分析(转)
原文:http://www.csdn.net/article/2010-07-26/277273 继成功举办首期TUP活动后,日前在北京丽亭华苑酒店鸿运二厅,由CSDN和<程序员> 杂志联 ...