好久没写笔记了
可并堆是个简单好用(好写)的数据结构
做了几道水题
luogu2713 罗马游戏
luogu3377 【模板】左偏树(可并堆)
luogu3066 [Usaco2012 Dec]Running Away From the Barn
可并堆的核心就是保持深度(要肤浅!)
最无脑的斜堆就是每次将左右孩子交换,但这是均摊log的(不会证啊)
也可以随机交换(rand()&1)
优秀(可持久化)的做法是维护一个dist,表示这个点向右能走的距离
要求满足dist_left>=dist_right,dist=dist_right+1
容易证明是log的,这就是左偏树(因为向左偏,斜堆也是向左偏的。。)
实测感觉斜堆跑得最快(数据不够优秀?)
几个错误:
不能merge两个处于同一个堆里的东西!(会翻倍诶)
swap(x,y)而不是swap(t[x],t[y]),因为要保证编号和值对应!
luogu2475 [SCOI2008]斜堆
(关于斜堆的一些性质,了解一下)
转自MATO IS NO.1
考虑斜堆中最后插入的那个结点,容易发现:
(1)它一定是一个极左结点(就是从根往它的路上一直都是沿着左链走),因为插入的时候每次都是插入到左子树中;
(2)它一定木有右子树,因为插入的时候每次都是把原来的某棵子树作为新结点的左子树;
满足(1)(2)的结点可能有多个,但紧接着可以发现,这个斜堆中的每个结点如果木有左子结点,那么也木有右子结点(或者说,每个非叶结点都有左子树),而在插入一个结点之前,其所有的祖先都被交换了左右子树,所以,若新结点的祖先中有满足(1)(2)的,且新结点不是叶结点,那么在新结点插入之前,这个满足(1)(2)的祖先必然是只有右子树而木有左子树的,这与上面的那个性质矛盾,所以,可以得出:最后插入的那个结点一定是满足(1)(2)的结点中,深度最小的那个(设为X),除非X的左子结点是叶结点,此时为了满足字典序最小,应该取X的左子结点为最后插入的。找到这个最后插入的结点以后,只需要把它删掉,并把它的所有祖先交换左右子树,就是插入该结点以前的状态了。这样可以找到字典序最小的插入顺序。