zoukankan      html  css  js  c++  java
  • 划分树[各种转载]

      盗了别人的资料。。。

    其实看下面的一个图片就知道划分树的结构了,和归并排序极为相似:

      注意:一定要注意其中中位数有多个相同的情况,需要统计。例如,上图第一次操作,只有一个3到了左区间。

    下面是具体的讲解:

    TonyShaw
        如果对于一段区间,仅查找一次第k大元素的话好说,直接一个快排搞定。

        如果有多次离线询问,然后就可以通过归并排序,建一棵归并树(nlogn)对于树的每一个节点,通过归并排序递归的建立一个序列,其中每个节点[l,r]表示原序列中,[l,r]这些数字排序以后的状态。如图,红色节点表示会被分到左子树。

               
        就这样,在区间[l,r]查找第k大元素的时候,先二分枚举元素x,求出x为第几大元素,再在归并树里查找相应区间,对于每一个被包含的区间,二分查找有多少个比当前枚举的元素x小,有多少元素小于等于当前枚举元素x,如果k刚好在这两段区间里,x就是第k大数。程序巨猥琐于是我没写- -!总体复杂度n(logn)^3……强烈膜拜想出此算法的。
    下面是本文重点:我不想写上面巨猥琐无比的算法,但是还要把题做出来,就从网上找资料,听说有个nlogn算法,叫做划分树。无奈资料巨少无比,只有某牛人的C++代码(一开始没看代码,光想下一位神牛的算法了,然后傻了……,代码写的很好,查找元素的函数对我帮助很大)和某“神牛”错误描述(此神牛浪费我2天时间,就是因为那个错误算法)。自己同样“yy3天后总算有点眉目,也不知道是不是传说中的划分树,不过复杂度nlogn应该是没错,“划分树和归并树差不多,不过节点定义不太一样。
    划分树指的是,每一个节点保存区间[l,r]所有元素,元素排列顺序与原数组相同,但是两个子树的元素为该节点所有元素排序后前(r-l+1)/2个进入左子树,其余的到右子树,同时维护一个sum域,sum[i]表示l--i这些点中有多少个进入了左子树。
    图片如下:
    红色表示该元素要进入左子树。树的建立很简单,我的方法比较笨- -!先排序,然后递归建树l等于r时直接赋值为sorted[l],否则先处理其左右孩子,然后将其孩子安在原数组中的顺序在该节点排列,总而言之建树怎么都行,只要出来是上面这个图并且能完美的维护sum域就行。

    查找其实是关键,因为再因查找[l,r]需要到某一点的左右孩子时需要把[l,r]更新。具体分如下几种情况讨论:
    假设要在区间[l,r]中查找第k大元素,t为当前节点,lch,rch为左右孩子,left,mid为节点t左边界和中间点。
    1、sum[r]-sum[l-1]>=k,查找lch[t],区间对应为[left+sum[l-1],left+sum[r]-1]。
    2、sum[r]-sum[l-1]<k,查找rch[t],区间对应为[mid+1+l-left-sum[l-1],mid+r-left+1-sum[r]]。

  • 相关阅读:
    Linux内核网络协议栈优化总纲
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 链表数据求和操作
  • 原文地址:https://www.cnblogs.com/zhsl/p/3035376.html
Copyright © 2011-2022 走看看