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

游程编码的基本原理是:用一个符号值或串长代替具有相同值的连续符号(连续符号构成了一段连续的“行程”。游程编码因此而得名),使符号长度少于原始数据的长度。只在各行或者各列数据的代码发生变化时,一次记录该代码及相同代码重复的个数,从而实现数据的压缩。

游程编码(Run Length Encoding , RLE)

例如:5555557777733322221111111

游程编码为:(5,6)(7,5)(3,3)(2,4)(1,7)

解题思路很好:

用value[i] count[i] 分别表示 第i段的数值 和 出现次数;

num[p] left[p] right[p]分别表示位置p所在段的编号和左右端点的位置。

每次查询(left,right)的结果为以下三个部分的最大值:从left到left所在段结束处的元素个数、从right所在段开始到right处的元素个数、中间第num[left]+1段到第num[right]-1段的count的最大值。

特殊情况:如果left和right在同一段中,答案是R-L+1。

解决方法如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100001;

int n,q;
int d[maxn][35];
int a[maxn];
int value[maxn],count_[maxn];
int num[maxn],left[maxn],right[maxn];

void RMQ_int(){
    for(int i=0;i<n;i++) d[i][0]=count_[i];
    for(int j=1; (1<<j)<=n; j++)
        for(int i=0; i+(1<<j)-1<n; i++)
            d[i][j]=max(d[i][j-1],d[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(d[L][k],d[R-(1<<k)+1][k]);
}
int main()
{
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        scanf("%d",&q);
        memset(count_,0,sizeof(count_));
        memset(num,0,sizeof(num));
        memset(left,0,sizeof(left));
        memset(right,0,sizeof(right));
        memset(d,0,sizeof(d));
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        int temp = a[0];
        int t=0;
        value[t]=temp;count_[t]++;
        num[0]=t;left[0]=0;
        for(int i=1;i<n;i++){
            if(a[i]==temp){
                count_[t]++;
                num[i]=t;left[i]=left[i-1];
            }
            else{
                for(int j=left[i-1];j<i;j++){
                    right[j]=i-1;
                }
                temp = a[i];
                t++;
                value[t] = temp;count_[t]++;
                num[i]=t;left[i]=i;
            }
        }
        t++;
        for(int i=left[n-1];i<n;i++){
            right[i]=n-1;
        }

        RMQ_int();
        int left_,right_;
        int ans=0;
        for(int i=0;i<q;i++){
            scanf("%d%d",&left_,&right_);
            left_--;right_--;
            if(num[left_]==num[right_]) ans=right_-left_+1;
            else{
                ans=max(right[left_]-left_+1,right_-left[right_]+1);
                if(num[left_]+1 > num[right_]-1) ans=max(ans,0);
                else{
                    ans=max(ans,RMQ(num[left_]+1,num[right_]-1));
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
时间: 2024-10-14 04:51:03

uva 11235 Frequent values(游程编码+区间最小值查询)的相关文章

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)

题目链接: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)

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

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

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

【暑假】[实用数据结构]UVa11235 Frequent values

UVa 11235 Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11241   Accepted: 4110 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several qu

UVA 11235 (游程编码+ST算法)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23846 题目大意:给定一个升序序列,有q次询问,每次询问(L,R)出现最多的值的次数. 解题思路: 非常麻烦的题目.尽管一眼就能看出来是个RMQ. 关键在于如何转化为RMQ. 首先对序列进行游程编码,压缩成pos段. 编码的同时用num[i]记录当前点在段中编号,LB[i]记录在当前段的左边界,更新code[pos](当前段的容量) 编码之后O(n)扫一遍,用nu