文艺平衡树(splay模板)

题干:splay模板,要求维护区间反转。

splay是一种码量小于treap,但支持排名,前驱后继等treap可求的东西,也支持区间反转的平衡树。

但是有两个坏处:

1.splay常数远远大于treap以及stl中的set。

2.没有可持久化splay,但有可持久化treap。

下面是代码:

1.pushup以及pushdown

pushup用于维护某点所在子树大小。

void pushup(int u)
{
    tr[u].siz = tr[tr[u].ch[0]].siz + tr[tr[u].ch[1]].siz + 1;
}

一行。

pushdown用于标记下推。

void pushdown(int u)
{
    if(tr[u].mrk)
    {
        tr[u].mrk=0;
        swap(tr[u].ch[0],tr[u].ch[1]);
        tr[tr[u].ch[0]].mrk^=1;
        tr[tr[u].ch[1]].mrk^=1;
    }
}

2.rotate

rotate相当于treap中的lturn和rturn,是将x点转到他的父节点处。

void rotate(int x)
{
    int y = tr[x].fa;
    int z = tr[y].fa;
    int k = (tr[y].ch[1]==x);
    tr[x].fa = z,tr[z].ch[tr[z].ch[1]==y]=x;
    tr[y].ch[k] = tr[x].ch[k^1],tr[tr[x].ch[k^1]].fa = y;
    tr[y].fa = x,tr[x].ch[k^1]=y;
    pushup(y),pushup(x);
}

注意改变父子关系时的顺序问题,还有两个pushup,应该先pushup儿子后pushup父亲。

3.splay(splay核心操作)

splay(a,b),将a旋转到b的儿子处。

下面是双旋splay:

void splay(int x,int goal)
{
    while(tr[x].fa!=goal)
    {
        int y = tr[x].fa;
        int z = tr[y].fa;
        if(z!=goal)
            ((tr[z].ch[1]==y)&(tr[y].ch[1]==x))?rotate(x):rotate(y);
        rotate(x);
    }
    if(goal==0)rot=x;
}

代码中while中的if,机房普遍认为是为了维护整棵树的深度。

4.insert

码量比treap少很多:

void insert(int x)
{
    int u = rot,fa;
    while(u)fa=u,u=tr[u].ch[tr[u].v<x];
    u=++tot;
    if(fa)tr[fa].ch[x>tr[fa].v]=u;
    tr[u].fa = fa,tr[u].v = x,tr[u].siz = 1;
    splay(u,0);
}

5.查询排名

代码:

int query_kth(int k)
{
    int u = rot;
    while(1)
    {
        pushdown(u);
        int t = tr[tr[u].ch[0]].siz;
        if(t==k-1)return u;
        else if(t>=k)u=tr[u].ch[0];
        else k-=t+1,u=tr[u].ch[1];
    }
}

6.区间旋转

先查询前驱后继,然后把所在子树夹到前驱后继之间,一个标记解决问题。

void chg(int l,int r)
{
    l = query_kth(l);//前驱
    r = query_kth(r+2);//后继
    splay(l,0);splay(r,l);
    tr[tr[tr[rot].ch[1]].ch[0]].mrk^=1;
}

最后:

推极大极小,推极大极小,推极大极小!!!

全代码就不粘了。

原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9592046.html

时间: 2024-08-26 11:07:13

文艺平衡树(splay模板)的相关文章

洛谷 P3391 【模板】文艺平衡树(Splay)

题目背景 这是一道经典的Splay模板题--文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是 (1,2,?n?1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,r] 数据保证 1≤l≤r≤n 输出格式: 输出一行n个数字,表示原始序列经过m次变换后的结果

[bzoj3223]文艺平衡树(splay区间反转模板)

解题关键:splay模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; const int N = 100005; int ch[N][2],par[N],val[N],cnt[

Tyvj P1729 文艺平衡树 Splay

题目: http://tyvj.cn/p/1729 P1729 文艺平衡树 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 此为平衡树系列第二道:文艺平衡树 描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数

BZOJ3223: Tyvj 1729 文艺平衡树 [splay]

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3595  Solved: 2029[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次

bzoj3224 普通平衡树(splay 模板)

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 11427  Solved: 4878[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为

[BZOJ3223] [Tyvj1729] 文艺平衡树 (splay)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数 接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n Output 输出一行n个数字,表示原始序列经过m次变换后的结果 Sample Input 5 3 1 3

JZYZOJ1998 [bzoj3223] 文艺平衡树 splay 平衡树

http://172.20.6.3/Problem_Show.asp?id=1998 平衡树区间翻转的板子,重新写一遍,给自己码一个板子. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdlib> 7 using namespace std; 8 cons

bzoj3224 普通平衡树 splay模板

题目传送门 题目大意:完成一颗splay树. 思路:模板题,学着还是很有意思的. 学习splay树:蒟蒻yyb 该题模板:汪立超 #include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; int root,N=0,n,p,q; int fa[100001],c[100001][2],size[100001],sp[100001]; void

[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护的标准,而处理区间问题时,维护平衡树的应该是每个位置的下标,所以平衡树中序遍历时应该是当前区间的样子.例如: {1 2 3 4 5}翻转区间1 3,则中序遍历应该输出{3,2,1,4,5}. 提供splay和无旋Treap的做法. splay做法: 1 #include<bits/stdc++.h>

bzoj 3223 文艺平衡树 Splay 打标志

是NOI2003Editor的一个子任务 1 #include <cstdio> 2 #include <vector> 3 #define maxn 100010 4 using namespace std; 5 6 struct Splay { 7 int pre[maxn], son[maxn][2], siz[maxn], rev[maxn], root; 8 9 void update( int nd ) { 10 siz[nd] = siz[son[nd][0]]+si