Hdu 1806 Frequent values (数据结构_RMQ)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1806

题目大意: 给定一个不递减长度为n的序列,给定m个询问,每次询问[li,ri]内上镜率最高的那个数的出现次数。

解题思路:简单RMQ,因为序列不递减,所以这题变得十分简单。先从询问开始研究,要找[l,r]内出现最多的次数,其实可以把这个区间内每个数出现的次数压缩成一个数,比如[1,1,3,3,3,5]就压缩成[2,3,1],这样的话就可以在一开始就进行初始化,把每个数压缩成次数,然后记录每个数出现的第一个位置和最后一个位置,压缩的过程需要用到hash,将这个数映射到某个下标,留到后面自有妙用,具体过程见代码。

    上面的过程有个问题,如果区间的开始和结束的那个数所在的连续区间被切断,比如1,1,3,3,3,5,然后让我们询问【2,3】,那1被切断了,3被切断了,上面的方法似乎就不靠谱了,怎么办?把前后拿出来单独计算就好,计算时与这个数所在的区间头区间尾比较找出有多少个在询问的区间内就好。然后取区间头、区间中、区间尾的最大值即可ac。


测试数据:

10 7
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
1 2
3 6
7 7
8 10
 
5 5
1 2 3 4 5
1 1
5 5
1 3
2 4
1 5


代码:
#include <stdio.h>
#include <string.h>
#include <map>
#include <math.h>
using namespace std;
#define MAX 110000
#define max(a,b) (a)>(b)?(a):(b)


map<int ,int> mmap;
int n,m,arr[MAX],tot,ans;
struct node {
    
    int v,beg,end,cnt;
}brr[MAX*2];
struct RMQ {
    
    int  dp[MAX][18];
    void Create();
    int  Query(int l,int r);
}rmq;
void RMQ::Create() {
    
    int i,j;
    for (i = 1; i <= tot; ++i)
        dp[i][0] = brr[i].cnt;
    for (j = 1; (1<<j) <= n; ++j)
        for (i = 1; i + (1<<j) - 1 <= n; ++i)
            dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int RMQ::Query(int l, int r){
    
    int k = (int)(log(r-l+1.0)/log(2.0));
    return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
int GetHash(int x,int in) {
    
    //if (x < 0) return x + 100001;
    //else return x;
    if (mmap.find(x) == mmap.end()) {
     
        mmap[x] = ++tot;
        brr[tot].v = x;
        brr[tot].beg = in;
        brr[tot].cnt = 0;
        brr[tot-1].end = in - 1;
    }
    return mmap[x];
}


int main()
{
    int i,j,k,ta,tb,tc,a,b;

    
    while (scanf("%d",&n),n) {
        
        scanf("%d",&m);
        tot = 0,mmap.clear();
        for (i = 1; i <= n; ++i){
            
            scanf("%d",&arr[i]);
            k = GetHash(arr[i],i);
            brr[k].cnt++;
        }
        brr[tot].end = n;


        rmq.Create();
        for (i = 1; i <= m; ++i) {

            scanf("%d%d",&a,&b);
            if (arr[a] != arr[b]) {

                j = GetHash(arr[a],i);
                ta = brr[j].end - a + 1;    //获取前面一段的长度,可不进行查询
                k = GetHash(arr[b],i);
                tb = b - brr[k].beg + 1;    //获取后面一段的长度,可不进行查询
                ans = max(ta, tb);
                if (brr[j].end + 1 != brr[k].beg) {
                    //中间还有一些区间,必须查询
                    tc = rmq.Query(j + 1, k - 1);
                    ans = max(tc, ans);
                }
            }
            else ans = b - a + 1;
            printf("%d\n",ans);
        }
    }
}


本文ZeroClock原创,但可以转载,因为我们是兄弟。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值