我是从zoj的promlem classification里面找到这个题目的,开始时想不到什么好方法,企图从零开始一步一步建树。最后还是没想到建树的算法。 后来查zoj forum,有人提到cartesian tree,于是google到了这方面的算法和数据结构。cartesian tree又叫randomized binary search tree,它是节点带权的二叉树,在插入新节点时,并非像平衡树那样做rebalance,而是维持父节点和子节点之间的权的大小关系(heap order),即要么父节点的权总是大于子节点的权,要么反之。NIST的网站还介绍了cartesian tree节点的插入和删除算法。大致如下: 插入:
删除:
然而直接的建立cartesian tree会导致超时,假设最终的树的所有节点都只有右孩子,并且插入时,总是插入最右节点,那复制度将会是O(n!)。
-------------------------------------------------------------------------------- 后来又经过查阅资料,发现可以用qsort+RMQ的方法。首先,对所有的节点,以key值排序,这样得到的结果为最终cartesian tree的中序遍历。再根据priority值,从上到下找到根节点,以及根节点的左右子树的根节点。。。 其中时间的消耗是:排序时间+找所有子树的根的时间。快速排序的平均复杂度为O(nlog2(n)),而利用RMQ可以在O(nlog2(n))内建立RMQ的矩阵,并在O(1)时间内查找任意范围内的最大priority节点对应的索引。 RMQ算法主要分两部分:(1)建立RMQ的matrix,(2)查找 (1)需要计算matrix[i][j]其中1<=i<=n, 0<=j<=[log2(n)](上去整) matrix[i][j]的含义为从i开始的宽度为2^j的范围内,priority最大的节点的位置 { matrix[i][j-1] priority(matrix[i][j-1]) > priority(matrix[i+2^(j-1)][j-1]) matrix[i][j] ={ { matrix[i+2^(j-1)][j-1] 否则 (2)查找RMQ(i, j),RMQ(i, j)的含义为从i开始到j为止的范围内,priority最大的节点的位置 计算k=max{r|2^r < j-i+1} { matrix[i][r] priority(matirx[i][r]) > priority(matrix[j-2^r+1][r] RMQ(i, j) = { { matrix[j-2^r+1][r] 否则 -------------------------------------------------------------------------------- 此问题还有一种最快的方法。考虑到对所有的输入节点做针对key的排序后,得到的数组为cartesian tree的中序遍历。
--------------------------------------------------------------------------------
最后给一下结果:第一种方法超时,RMQ为0.95秒,最后一种方法为0.51秒.