UVA 11235--Frequent values+RMQ问题

题目链接:点击进入

以前也碰到过不需要修改,只需要单纯查询区间最值的题目,那时候都是用的线段树做的。但是现在大白书上提供了一个更好的算法。

当然这个题目本身还是不能直接套最大最小值的模板的,需要做一些转换。其中最主要的就是要将题目给的数据,处理成(a,b)这种格式,表示数字a连续出现b次,并且记录每个编号对应的段号。然后我们在处理过后的以段为表示单位的数据上进行RMQ查询了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

#define maxn 100100

int value[maxn],cnt[maxn];
int num[maxn],left1[maxn],right1[maxn];
int dp[maxn][30],a[maxn];

void RMQ_Init(int t)
{
     int n=t;
     for(int i=0;i<n;i++)
        dp[i][0]=cnt[i];
     for(int j=1;(1<<j)<=n;j++)
       for(int i=0;i+(1<<j)-1<n;i++)
           dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}

int RMQ(int L,int R)
{
     int k=0;
     while((1<<(k+1)) <=R-L+1) k++;
     return max(dp[L][k],dp[R-(1<<k)+1][k]);
}

int main()
{
     int n,q;
     freopen("in.txt","r",stdin);
     while(scanf("%d",&n)&&n)
     {
          scanf("%d",&q);
          for(int i=0;i<n;i++)
              scanf("%d",&a[i]);
          left1[0]=0;
          int t=0,tmp=1;
          for(int i=1;i<n;i++)
          {
               if(a[i]!=a[i-1])
               {
                   right1[t]=i-1;
                   value[t]=a[i-1];
                   cnt[t]=tmp;
                   t++;
                   num[i]=t;
                   left1[t]=i;
                   tmp=1;
               }
               else
               {
                   tmp++;
                   num[i]=t;
               }
          }
          right1[t]=n-1;
          value[t]=a[n-1];
          num[n-1]=t;
          cnt[t]=tmp;
          RMQ_Init(t);
          while(q--)
          {
                int x,y;
                scanf("%d%d",&x,&y);
                x--; y--;
                int L=num[x],R=num[y];
                if(L==R)
                {
                    printf("%d\n",y-x+1);
                    continue;
                }
                int max0=0;
                max0=max(right1[L]-x+1,y-left1[R]+1);
                if(R-1>=L+1)
                    max0=max(max0,RMQ(L+1,R-1));
                printf("%d\n",max0);
          }
     }
  return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-24 04:13:21

UVA 11235--Frequent values+RMQ问题的相关文章

uva 11235 - Frequent values(RMQ)

题目链接:uva 11235 - Frequent values 题目大意:给定一个非降序的整数数组,要求计算对于一些询问(i,j),回答ai,ai+1,-,aj中出现最多的数出现的次数. 解题思路:因为序列为非降序的,所以相同的数字肯定是靠在一起的,所以用o(n)的方法处理处每段相同数字的区间.然后对于每次询问: num[i]=num[j]:j?i+1 numi≠numj:max(RMQ(righti+1,reftj?1),max(righti?i+1,j?leftj+1)) #include

UVa 11235 Frequent values (RMQ &amp;&amp; 区间出现最多次的数的次数)

题意 : 给出一个长度为 n 的不降序序列,并且给出 q 个形如(L, R)的问询,问你这个区间出现的最多次的数的次数. 分析 : 很自然的想到将区间"缩小",例如1 1 2 3 3 3就可以变成2 1 3,构造出"数量数组",这个数组实际上就是已经将原来区间分了块,但是问询的区间不可能就是这些"数量数组"构成的"块",不过先来想想问询的区间可不可能包含这里面的某些"块"?很显然是有可能的,那么从这些&qu

UVA 11235 Frequent values(RMQ)

Frequent values TimeLimit:3000Ms You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most f

UVA 11235 Frequent values

1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int maxn=100005; 7 8 int count[maxn]; 9 int num[maxn],ll[maxn],rr[maxn]; 10 int tot; 11 int d[maxn][50]; 12 13 int rmq (int l,int r){ 14 int

UVA 11235 Frequent values 线段树/RMQ

vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释************************************************************ 题目大意:给出一个非降序排列的整数数组 a1,a2,a3,...,an,你的任务是对于一系列询问 (i, j),回答 ai,ai+1,...,aj 中出现次数最多的值所出现的次数. 输入格式:包含多组数据.每组

UVA - 11235 —— Frequent values 【RMQ】

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23846 题解: 1. 游程编码(将序列转化为(value, num)的一段一段的键值对形式)后,将问题转化为几乎是一个RMQ问题,仅有一些细节要单独考虑 2. 如果查询的两个下标l, r属于同一段键值对,那么答案就是(r - l + 1):否则,答案是三个(或两个)值的最大值,详情见代码: #include <iostream> #include <cstdio&g

uva 11235 Frequent values(游程编码+区间最小值查询)

游程编码的基本原理是:用一个符号值或串长代替具有相同值的连续符号(连续符号构成了一段连续的"行程".游程编码因此而得名),使符号长度少于原始数据的长度.只在各行或者各列数据的代码发生变化时,一次记录该代码及相同代码重复的个数,从而实现数据的压缩. 游程编码(Run Length Encoding , RLE) 例如:5555557777733322221111111 游程编码为:(5,6)(7,5)(3,3)(2,4)(1,7) 解题思路很好: 用value[i] count[i] 分

(线段树区间合并)UVA 11235 - Frequent values

题意: 一个数列,多次查询L到R最多连续相同数字的数量. 分析: 显然区间合并.不过还就没写了,都有点忘了. 不过回忆一下,push_down还是写对了. 不过WA了,后来仔细想一想,光查询光用已经维护的答案还不够,还需要在query的时候再合并一下,才能更新出正确的答案. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #

POJ 3368 Frequent values RMQ ST算法/线段树

                                                     Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15229   Accepted: 5550 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In

poj 3368 Frequent values(RMQ)

1 /************************************************************ 2 题目: Frequent values(poj 3368) 3 链接: http://poj.org/problem?id=3368 4 题意: 给出n个数和Q个询问(l,r),对于每个询问求出(l,r)之 5 间连续出现次数最多的次数 6 算法: RMQ 7 思路: 借助数组f[i].表示第i位前面有f[i]个相同的数.对于 8 每个区间(l,r).暴力求前面几个