第三章例题8 (频繁出现的数值)RMQ

来源:互联网 发布:做美工需要学什么 编辑:程序博客网 时间:2024/06/06 19:11

给你长度为n的非递减数组,m次询问,问[l,r]内出现最多的值所出现的次数。  可交题的链接

题解:

真是好题,书上刚讲了RMQ,然后给出这道题,我一看两者也没啥联系啊,后来才知道,通过变化, 就是一道RMQ题。

因为是非递减的,所以相等的元素一定是连续出现的,然后我们记录每个连续块的数值(value),长度(coun),左端点(lef),右端点(righ),以及每个数属于哪个连续块(num)。然后coun上做RMQ,对于每一次询问(L,R),如果L,R属于同一个连续块,则长度问R-L+1,否则,如果L,R之间有超过两个连续块,就得RMQ求一下,区间最值,然后再判断,不完整区间的长度。取最大即可

代码:

#include <stdio.h>#include <stdlib.h>#include <iostream>#include <string.h>#include <math.h>#define ll long longusing namespace std;const int maxn=1e5+10;int maxnum[maxn][50];int value[maxn];int coun[maxn];int lef[maxn];int righ[maxn];int num[maxn];int a[maxn];void RMQ(int num){    for(int i=1; i<=num; i++)    {        maxnum[i][0]=coun[i];    }    for(int j=1; j<20; j++)    {        for(int i=1; i<=num; i++)        {            if(i+(1<<j)-1<=num)            {                maxnum[i][j]=max(maxnum[i][j-1],maxnum[i+(1<<(j-1))][j-1]);                //  minnum[i][j]=min(minnum[i][j-1],minnum[i+(1<<(j-1))][j-1]);            }        }    }}int remax(int st,int en){    int k=(int)((log(en-st+1))/log(2.0));    return max(maxnum[st][k],maxnum[en-(1<<k)+1][k]);}int n,m,l,r;int main(){    while(~scanf("%d",&n))    {        if(!n)break;        scanf("%d",&m);        int len=1;        memset(a,0,sizeof(a));        scanf("%d",&a[1]);        value[len]=a[1];        coun[len]=1;        num[1]=len;        lef[len]=1;        for(int i=2; i<=n; i++)        {            scanf("%d",&a[i]);            if(a[i]==a[i-1])            {                coun[len]++;                num[i]=len;            }            else            {                righ[len]=i-1;                len++;                value[len]=a[i];                coun[len]=1;                num[i]=len;                lef[len]=i;            }        }        RMQ(len);        while(m--)        {            scanf("%d%d",&l,&r);            if(num[l]==num[r])            {                printf("%d\n",r-l+1);            }            else            {                int ans=0;                if(num[l]+1<=num[r]-1)                {                    ans=remax(num[l]+1,num[r]-1);                }                    ans=max(ans,max(righ[num[l]]-l+1,r-lef[num[r]]+1));                    printf("%d\n",ans);            }        }    }}


0 0
原创粉丝点击