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)扫一遍,用num[i]、code[num[i]]和LB[i]搞出在当前段的右边界RB[i]。

则Q(L,R)的时候有以下几种情况:

①如果num[L]=num[R],则说明L,R在同一段,ans=R-L+1。

②如果num[L]≠num[R],则说明L,R不在同一段,

则整个(L,R)被划分成三段:(L,RB[L]-L+1)这些元素在同一个段中,(num[L]+1,num[R]-1)前提是num[L]+1<=num[R]-1,(R-LB[R]+1,R)这些元素在同一个段中。

由于左右段都在同一段中,max元素个数即可。中间这段混合了多个完整的段,直接st即可,注意st初始化的是段的容量。

#include "cstdio"
#include "cstring"
#include "iostream"
using namespace std;
#define maxn 100000
#define maxp 20
int RMQ[maxn][maxp],n,q,w,l,r,code[maxn],num[maxn],LB[maxn],RB[maxn];
template <class T>
inline bool read(T &ret)
{
    char c;
    int sgn;
    if(c=getchar(),c==EOF) return 0; //EOF
    while(c!=‘-‘&&(c<‘0‘||c>‘9‘)) c=getchar();
    sgn=(c==‘-‘)?-1:1;
    ret=(c==‘-‘)?0:(c-‘0‘);
    while(c=getchar(),c>=‘0‘&&c<=‘9‘) ret=ret*10+(c-‘0‘);
    ret*=sgn;
    return 1;
}
void ST()
{
    for(int i=1;i<=n;i++) RMQ[i][0]=code[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
           RMQ[i][j]=max(RMQ[i][j-1],RMQ[i+(1<<(j-1))][j-1]);
}
int Query(int L,int R)
{
    int k=0;
    while((1<<(k+1))<=R-L+1) k++;
    return max(RMQ[L][k],RMQ[R-(1<<k)+1][k]);
}
int Q(int L,int R)
{
    if(num[L]==num[R]) return R-L+1;
    else
    {
        int a=RB[L]-L+1;
        int b=0;
        if(num[L]+1<=num[R]-1) b=Query(num[L]+1,num[R]-1);
        int c=R-LB[R]+1;
        return max(max(a,b),c);
    }
}
int main()
{
    while(read(n)&&read(q)&&n)
    {
        memset(RMQ,128,sizeof(RMQ));
        memset(code,0,sizeof(code));
        int pos=0,last=1<<28;
        for(int i=1;i<=n;i++)
        {
             read(w);
             if(w==last)
             {
                 LB[i]=LB[i-1];
                 code[pos]++;//当前段容量
             }
             else
             {
                 LB[i]=i; //左边界
                 code[++pos]=1;
                 last=w;
             }
             num[i]=pos; //当前点段编号
        }
        for(int i=1;i<=n;i++) RB[i]=LB[i]+code[num[i]]-1; //右边界
        n=pos;
        ST();
        for(int i=1;i<=q;i++)
        {
            read(l);read(r);
            printf("%d\n",Q(l,r));
        }
    }
}

2809497

neopenx

UVA 11235

Accepted

0 KB

182 ms

C++ 4.8.2

1827 B

2014-10-03 18:18:58

时间: 2024-10-14 09:51:01

UVA 11235 (游程编码+ST算法)的相关文章

UVA 11235 Frequent values 线段树/RMQ

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

RMQ问题——ST算法

什么是RMQ.ST:RMQ(Range Minimum/Maximum Query)问题,即求区间的最值.可以写一个线段树来实现,但是每次查询的时间复杂度为O(log n),若查询次数过多则可能超时.ST算法是一种离线算法,经过O(nlogn)的预处理后,可以在O(1)的时间复杂度内进行查询,缺点是无法对数据做出修改. 算法实现: 初始化:用dp实现初始化.a[]为原始数据数组f,[i][j]表示从i向后的2j个数字中的最值.显然f[i][0]=a[i]; 我们将f[i][j]分为两段,一段为a

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

[POJ] 3264 Balanced Lineup [ST算法]

Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 34306   Accepted: 16137 Case Time Limit: 2000MS Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer Joh

理解RMQ问题和ST算法的原理

下图为TI C6xx DSP Nyquist总线拓扑图,总线连接了master与slave,提供了高速的数据传输.有很多种速率不同的总线,如图中的红色方框,最高速总线为CPU/2 TeraNet SCR(即VBUSM SCR),带宽为256bit,其他低速总线为CPU/3,CPU/6,带宽参考图中所示.总线之间用Bridge(桥)连接,作用包括转换总线的速率,使之与所流向总线的速率相同等. 在具体应用中,各种速率的总线完全可以满足复杂的数据传输,而数据传输的瓶颈往往在于连接总线之间的Bridge

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

hdu5289 Assignment (区间查询最大值最小值,st算法...)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5289 题意:给定长度为n的序列a和一个整数K,找出最大值和最小值的差值小于K的区间.输出满足条件的区间的个数. 分析:枚举a[i],以a[i]为起点,然后二分找终点(大区间满足条件的话小区间肯定也满足),依据起点和终点的位置能够算出以a[i]为起点可满足条件的区间的个数.怎么推断区间是否满足条件?能够用st算法用O(N*logN)方法进行预处理,然后O(1)查询区间最大值可最小值.先前用线段树查询超时了

RMQ问题之ST算法

RMQ问题之ST算法 RMQ(Range Minimum/Maximum Query)问题,即区间最值问题.给你n个数,a1 , a2 , a3 , ... ,an,求出区间 [ l , r ]的最大值. 举例:a={ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 },求出区间[4 ,8]中的最值.(答案:8 ) 这个问题最朴素的想法是用一个循环每次比较大小,但是,当数据范围较大时,这个算法十分低效.这时我们往往使用 ST 算法解决这个问题.虽然线段树和树状数组都能解决,但

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