关于分桶法(平方分割)的一些见解

 

分桶法:给一个n个元素的数组a[0...n],分桶法的思想是将这n个元素进行均分,均分成√n组,每组里有√n个元素,这里“组”的意思与“桶”等价。这种分法也称之“平方分割”。

这样会带来哪些处理上的好处呢?其实类似于线段树,分桶法的思想也是每个桶分别维护各自桶内部的信息,然后在处理区间问题上带来快捷。这里以RMQ(Range Minimum Query)为例:

  给出一个n个元素的数组a[],我们的任务有两个:

  • 给定l,r,我们要答出区间[l,r]上的最小值;
  • 给定i,x,我们要将a[i]替换成x.

  这里我们用b代表”桶宽“,取b=[√n], 然后依次在每个桶中放入b个元素:

    b=(int) sqrt(n);
    vector<int> bucket[MAX_N/b];
    for(int i=0;i<n;i++) {
        bucket[i/b].push_back(a[i]);
    }

  每个桶所维护的便是它的区间里的最小的数,记为val[i]

  任务1:查询

  •   若所查询的区间[l,r]完全的包含了桶bucket[i],则直接查询桶bucket[i]所维护的那个值;
  •        若所查询的区间[l,r]与桶bucket[i]有交集但并不完全包含该桶(或者说桶i仅有一部分在[l,r]中),这时我们便遍历该桶在查询区间[l,r]中的那一部分。

  而查询区间[l,r]时,我们需要遍历的元素个数不超过n/b个,这部分的复杂度是O(√n);而询问各个桶维护的最小值所要的复杂度也是O(√n),所以查询时的总的复杂度是O(√n)

  任务2:更新

  • 更新元素时,直接遍历一遍更新后的桶中的值,得出最小值即可

  //值得注意更新时不可以采用x与桶k维护的值val[k]直接比较取min{val[k],x},因为桶不知道替换掉的是谁,可能是val[k]所在的a[i]x替换了(不过感觉大家不会出这种错啦~

  更新时仅需遍历一个桶,因此其复杂度也是O(√n)

 

  这样,如果总的操作数是m,那么总的操作复杂度就是O(m√n),条件不苛刻是还是推荐使用的,毕竟实现起来比线段树简单。

  

  推荐题目:K-th Number(POJ 2104)

 

  

 

 

  

posted @ 2018-01-26 02:04  Keynman  阅读(801)  评论(0编辑  收藏  举报