Treap名字的来源:Tree+Heap,正如名字一样,就是一颗简单的BST,一坨堆的合体。BST的不平衡的根本原因在于基于左<=根<=右的模式吃单调序列时候会无脑成长链,而Treap则添加一个优先级属性,值的大小随机生成,用最大堆的方式维护。之所以使用堆,是因为堆是一颗 完全二叉树,而BST梦寐以求的就是完全二叉结构,二者一结合,就产生了一种新的Balanced BST。Treap依赖于随机数,随机生成的优先级属性,通过简单的左右旋可以将长链旋转成近似完全二叉树结构,注意只是近似,平均情况下的树高是(log 1.46n),但是完全二叉是(log 2n),可以说还是有一点点差距的,不过基本接近红黑树的平衡状况。鉴于比红黑树好拍,而且可塑性很强(如果你是用STL红黑树),在不是很追求鲁棒性的前提下,Treap算是神器了。

常规的BST用不着Treap,Treap的一大作用是求第K大数,具体方法是每个结点维护一个附加信息s,s为所有子结点和自身结点的数量,形成一颗 Rank Tree(名次树),如果你是手拍红黑树,可以自己实现,用不着Treap。但是如果使用STL,STL高度封装特性使得我们无法定制自己的树,这点着实 蛋疼。记住Treap的优势:简化的可定制的红黑树!

先来介绍一下Treap的结点结构。

struct node
{
node *ch[];
int v,r,s; //v-value,r-random值,s-附加结点信息
int cmp(int x)
{
if(x==v) return -;
return x<v?:; //0-left,1-right
}
void maintain() //维护附加信息s
{
s=;
if(ch[]!=NULL) s+=ch[]->s;
if(ch[]!=NULL) s+=ch[]->s;
}
}

Treap的结点结构

Treap的主操作由以下几部分构成:rotate、insert,remove。

void rotate(node* &o,int d)
{
node *k=o->ch[d^];o->ch[d^]=k->ch[d];k->ch[d]=o;
o->maintain();k->maintain();o=k;
}

rotate操作

void insert(node* &o,int x)
{
if(o==NULL)
{o=new node;o->ch[]=o->ch[]=NULL;o->v=x;o->r=rand();o->s=;}
else
{
int d=x<o->v?:; //不使用cmp的原因:可能有重复元素
insert(o->ch[d],x);
if(o->ch[d]->r > o->r) rotate(o,d^);
}
o->maintain();
}

insert操作

void remove(node* &o,int x)
{
int d=o->cmp(x);
if(d==-)
{
if(o->ch[]!=NULL&&o->ch[]!=NULL)
{
int d2=o->ch[]->r>o->ch[]->r?:;
rotate(o,d2);
remove(o->ch[d2],x);
}
else {if(o->ch[]==NULL) o=o->ch[];else o=o->ch[];}
}
else remove(o->ch[d],x);
if(o!=NULL) o->maintain();
}

remove操作

remove的操作比较繁点,分为三种情况:

1.左右子树都存在,得让左右结点较大的r转到根,然后移出原来的根。

2.左右子树存其一,根直接改成左/右即可。

3.左右子树不存在,直接NULL即可。

然后就是RankTree的操作:kth

int kth(node *&o,int k)
{
if(o == NULL || k<= || k>o->s) return ;
int s = (o->ch[] == NULL ? : o->ch[]->s);
if(k == s + ) return o->v;
else if(k<=s) return kth(o->ch[],k);
else return kth(o->ch[],k-s-);
}

kth操作

@练习题

LA5031,查询指定点连通的第K大数。首先得明白连通≠邻接,所以查询某个点的连通点,得从该点的root进行。本题中虽然说是图,但是必须清 楚,图可以由多棵Tree合成。方法是先保持所有结点独立,各自为一颗Tree,然后对于有边的u、v,进行两颗Tree的合并操作。由于合并的时候要批 量修改父节点,这里借助于并查集完成操作。最麻烦的是删除指定一条边,如果正向处理,代码要写好多行。这里借助逆向操作,变删除为添加,就好办多了。注 意,一旦逆向后,原本修改结点的操作也要反过来。cmd里保存的是现有w的之前的w,然后覆盖w,逆向处理的时候修改的之前备份的值,而不是应该修改的 值。

主要操作为addedge,merge,change,query。

merge(src,dest): 土法子,就是把src所有点取出来insert。递归src左右子树,然后将src根的值insert到dest里面,最后src赋值NULL

addedge(u,v) :先确认合并的u、v是否在同一集合,如果不在,将结点少的点merge到结点多的点里面(优化)。

change(x,v): 先确定目标点的root,remove掉值为x的点(??对LRJ的代码产生疑惑,题目说是将指定id的点修改,万一有相同的x,那不就删了多点?) 然后insert值为v的点,修改w保存的值。

query: 每次通过并查集定位指定点的root,然后做kth,累加统计。

Treap和名次树的更多相关文章

  1. Treap 实现名次树

    在主流STL版本中,set,map,都是BST实现的,具体来说是一种称为红黑树的动态平衡BST: 但是在竞赛中并不常用,因为红黑树过于复杂,他的插入 5 种,删除 6 中,代码量极大(如果你要改板子的 ...

  2. 模板——Treap实现名次树

    Treap 是一种通过赋予结点随机权值的一种满足堆性质的二叉搜索树,它很好的解决了二叉搜索树顺序插入组成链式的局限性. 名次树是指在treap的每个结点中添加附加域size,表示以它为根的子树的总结点 ...

  3. 「模板」「讲解」Treap名次树

    Treap实现名次树 前言 学平衡树的过程可以说是相当艰难.浏览Blog的过程中看到大量指针版平衡树,不擅长指针操作的我已经接近崩溃.于是,我想着一定要写一篇非指针实现的Treap的Blog. 具体如 ...

  4. bzoj3224 Tyvj 1728 普通平衡树(名次树+处理相同)

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5354  Solved: 2196[Submit][Sta ...

  5. uvalive 5031 Graph and Queries 名次树+Treap

    题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...

  6. UVa 1479 (Treap 名次树) Graph and Queries

    这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个 ...

  7. LA 5031 Graph and Queries —— Treap名次树

    离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1lo ...

  8. bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1807  Solved: 772[Submit][Stat ...

  9. UVaLive5031 Graph and Queries(时光倒流+名次树)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20332 [思路] 时光倒流+名次树(rank tree). 所谓“ ...

随机推荐

  1. Boltzmann机

    博客园不能上传附件,所以这里贴两张流程图吧.一个是模拟退火算法的流程图(Boltzmann机本实上就是反复退火的过程), 个是Boltzmann调整权值的过程.

  2. 让jar程序在linux上一直执行

    当我们把java程序打成jar包后,放到linux上通过putty或其它终端执行的时候,如果按照:java -jar xxxx.jar执行,当我们退出putty或终端的时候,xxxx.jar这个程序也 ...

  3. string s = null 和 string s = “”的区别

    string s = null; 表示一个空串,没有占用了空间,不在内存中开辟空间 string s = "";在内存中开辟空间,但空间中没有值(""也是一个字 ...

  4. EtherCAT数据帧结构

    EtherCAT数据直接使用以太网数据帧(以太网帧解释http://blog.chinaunix.net/uid-23080322-id-118440.html)传输,使用的帧类型为0x88A4.Et ...

  5. Linux下提取IP至文件

    ifconfig | grep 'inet[^6]' | sed 's/^\s*//g' | cut -d ' ' -f2 > ips.txt 排除127开头的IP: ifconfig | gr ...

  6. 2.设计包含 min 函数的栈[StackWithMinValue]

    [题目]: 定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素.要求函数min.push以及pop的时间复杂度都是O(1). [解法一]: 使用一个辅助栈来保存最小元素,其栈顶元素为当前栈 ...

  7. iOS UITableView 的beginUpdates和endUpdates

    在官方文档中是这样介绍beginUpdates的 Call this method if you want subsequent insertions, deletion, and selection ...

  8. CHM文档打开空白的解决

    网上打包的CHM格式的文档,有时候打开无论点击目录哪一章节都会出现一片空白或者显示已取消到该网页的导航 这个情况的原因就是CHM文件在Windows的HTFS文件系统中会默认被阻止显示,解决方法就是在 ...

  9. Java for LeetCode 072 Edit Distance【HARD】

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...

  10. CodeForces - 427B (模拟题)

    Prison Transfer Time Limit: 1000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u Sub ...