RMQ查询-ST算法

对于RMQ(Range Minimum Query)问题.给出一个n个元素的数组, {a1,a2,,,ai,,,an} ,对于查询操作Query(L,R),给出其中的 min{a1,a2,...,ai,...,an} ,
这里用一个简单的数据结构来解决这个问题,他的预处理只需要 O(n) ,对于查询只需要 O(1) .

Sparse-Table

di,j 表示从 i 开始,长度为 2j 的区间中的最小值,显然 di,j=min{di,j1,di+2j1,j1}

初始化

   void  RMQ_init(const int *A,int n)
{
  for(int i=0 ; i0] = A[i];

  for(int j = 1 ; (1<for(int i =0 ; i+(1<1min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}

查询


int RMQ(int L,int R)
{
    int k =0 ;
    if(Rreturn 0;
    while(1<<(k+1)<=R-L+1)k++;
    return min(d[L][k],d[R-(1<1][k]);
}

例题

Uva 11235
这个题可以预处理每一个数字的次数cnt[i]表示第i段的次数,这里的 i 表示的是按照每个不同数字分的段,并且记录下每一个数的起始编号和结束编号,
对于每一个段[L,R]来说,if ele[L].v = ele[R].v,则Query(L,R) = R-L+1,否则,query(L,R) = max{ele[L]出现的个数,ele[R]出现的个数,RMQ(ele[L]的后一段,ele[R]的前一段)}
给出主代码


int solve(int L,int R)
{
    int v;
    if(ele[L].v !=ele[R].v)
    {
         v = max(ele[L].right-L+1,R-ele[R].left+1);
    }else{
        return R-L+1;
    }
    int ans = RMQ(ele[L].num+1,ele[R].num-1);
    return max(ans,v);
}

int main()
{
    //freopen("H:\\c++\\file\\stdin.txt","r",stdin);
    while(scanf("%d",&n) && n)
    {
        scanf("%d",&q);
        for(int i=0 ; i"%d",&ele[i].v);
        }
        int top = 0;
        memset(cnt,0,sizeof(cnt));
        value[0] = ele[0].v;
        cnt[top]++;
        ele[0].left = 0;
        ele[0].num = 0;
        for(int i=1 ; iif(ele[i].v>value[top])
            {
                value[(++top)] = ele[i].v;
                ele[i].left = i;
            }else
            {
                ele[i].left = ele[i-1].left;
            }
            cnt[top]++;
            ele[i].num = top;
        }
        for(int i=0 ; i1;
        RMQ_init(cnt,top+1);
        int L,R;
        while(q--)
        {
            scanf("%d %d",&L,&R);
            int ans = solve(L-1,R-1);
            printf("%d\n",ans);
        }

    }
    return 0;
}

你可能感兴趣的:(算法理论)