I am a slow walker,but I never walk backwards. Abraham Lincoln

GeekZRF

分桶法和平方分割

分桶法:把一排物品或者平面分成桶,每个桶分别维护自己内部的信息,已到达高效计算的目的的方法。

 

其中,平方分割是把排成一排的n个元素每√n个分在一个桶内进行维护的方法的统称。这样的方法可以使对区间的操作复杂度降至O(√n)。

以RMQ为例:

基于平方分割的RMQ

给定一个数列a1,a2,a3,a4,a5,a6,....,an,目标是在O(√n)浮渣度内实现以下两个功能

  • 给定s,t,求as,as+1,as+2,...,at的最小值。
  • 给定i,x,把ai的值变成x。

基于平方分割的RMQ预处理

令len=(int)(√n),把a中的元素每len个分成一个桶,并且计算出每个桶内的最值。

 

基于平方分割的RMQ查询

如下图所示,查询

  • 如果桶完全包含在区间内,则查询桶内的最小值。
  • 如果元素所在的桶不完全被包含包含,则逐个检查最值。

它们的最值就是区间的最值了。

 

 

基于平方分割的RMQ的值的更新

在更新元素的值时,只需要更新该元素所在的桶的最值。

 

基于平方分割的RMQ的复杂度

在更新时,因为每个桶内有len个元素,所以复杂度是O(len)=√n

而在查询时

  • 完全包含在区间内的桶的个数是O(n/len)
  • 所在的桶不被区间完全包含的元素个数是O(len)

因为len=O(√n),所以操作复杂度是O(n/len+len)=O(√n+√n)=O(√n

 

附上POJ 3246.Balanced Lineup的平方分割的RMQ写法

代码:

#include <iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<set>
using namespace std;
#define PI acos(-1.0)
typedef long long ll;
typedef pair<int,string> P;
const int maxn=1e5+100,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=1e13+7;
priority_queue<P,vector<P>,greater<P> >q;
struct edge
{
    int from,to;
    int cost;
};
///分桶法+平方分割解决RMQ问题
struct node
{
    int l,r;
    int mmin,mmax;
} sign[maxn];
int a[maxn];
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    int x=(int)(sqrt(n));
    int t=0;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        if(i%x==1) t++,sign[t].l=i,sign[t].r=i,sign[t].mmax=0,sign[t].mmin=inf;
        sign[t].mmin=min(sign[t].mmin,a[i]);
        sign[t].mmax=max(sign[t].mmax,a[i]);
        sign[t].r=i;
    }
    while(q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        int mmax=0,mmin=inf;
        for(int i=1; i<=t; i++)
        {
            if(l>sign[i].r) continue;
            if(l>sign[i].l)
            {
                for(int j=l; j<=sign[i].r&&j<=r; j++)
                    mmax=max(mmax,a[j]),mmin=min(mmin,a[j]);
            }
            else if(l<=sign[i].l&&sign[i].r<=r)
                mmax=max(mmax,sign[i].mmax),mmin=min(mmin,sign[i].mmin);
            else if(r<sign[i].r)
            {
                for(int j=sign[i].l; j<=r; j++)
                    mmax=max(mmax,a[j]),mmin=min(mmin,a[j]);
            }
            if(r<=sign[i].r) break;
        }
        cout<<mmax-mmin<<endl;
    }
    return 0;
}
平方分割的RMQ

 

posted on 2017-07-08 13:48  GeekZRF  阅读(373)  评论(0编辑  收藏  举报

导航