UVA 11235-Frequent values-RMQ(st表)+游程编码

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23846

本题数据下,ST表和线段树都是100+ms 差别不大 

题目大意:
给一个非降序排列的整数数组a,你的任务是对于一系列询问(i, j),回答ai,ai+1...aj中次数出现最多的值所出现的次数。

预处理是先把所有相同的元素合并成一个node,node含该元素编号+该元素个数  ( 称为表2)

并且记录好位置i对应的是预处理后的第i个node

对每次查询(a,b)

只需要把a,b位置对应的  表2 中的编号之间的所有 node ,对这些node的元素个数求一个RMQ,记为tmp1

然后a对应的node 的右端点-a+1  ,记为tmp2  (即元素值为a的可计算的个数)

同理   b对应的node  b-左端点+1 ,记为tmp3  (即元素值为b的可计算的个数)

三者取最大即可

特殊情况,当a,b对应的node为同一个,那么只需要 输出b-a+1即可

 
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std; 
#include <iostream>
using namespace std; 

const int maxn=100005;
int ok;//ok个不同值的点
 
 int value [maxn],cun[maxn];//第i点的值,以及相同的个数
 int l[maxn],r[maxn];//第i个点的值在原序列中的左端点右端点
 int who[maxn];//标明这位置属于第i点的管辖
 int tm[maxn]; //原始数组

 int mx[maxn][16];//16开logn就好了,st表
 
int max(int a,int b)
{
	if (a<b)
	return b;
	return a;
}  
 void rmq_init()
 {
     int i,j;
     for(j=1;j<=ok;j++) mx[j][0]=cun[j];
     int m=floor(log((double)ok)/log(2.0));
     for(i=1;i<=m;i++){
         for(j=ok;j>0;j--){
             mx[j][i]=mx[j][i-1];
             if(j+(1<<(i-1))<=ok) mx[j][i]=max(mx[j][i],mx[j+(1<<(i-1))][i-1]);
         }
    }
   
 }
 
 int rmq_max(int l,int r)
 {
     int m=floor(log((double)(r-l+1))/log(2.0));
    int a=max(mx[l][m],mx[r-(1<<m)+1][m]); 
    return a;   //a为最大值
 } 


int main()
{ 
    int  t;
	int  n,m; 
	while (cin>>n)
	{
	
		if (!n) break;
				
		scanf("%d",&m); 
		memset(mx,0,sizeof(mx));

		int  i;
		for(  i = 1; i <= n; i++)
		{
			scanf("%d",&tm[i]); 
		} 
		 ok=0;
			for(  i = 1; i <= n; i++)
		{
			value[++ok]=tm[i];
			cun[ok]=1;
			who[i]=ok;
			l[ok]=i;
			while(tm[i+1]==tm[i])
			{
			
				cun[ok]++;
				i++;
				who[i]=ok;
			} 	
			r[ok]=i;
		} 
		rmq_init(); 
		int a,b;
	 	for(  i = 1; i <= m; i++)
		{
			scanf("%d%d",&a,&b); 
			int t1=who[a];  //t为a位置对应点的编号
			int t2=who[b];
			int tmp1=0;
			if (t2>t1+1)	//如果距离大于1 中间部分所有点的最大值作为比较参数,否则为0
				 tmp1=rmq_max(t1+1,t2-1); 

			int tmp2=r[t1]-a+1;//a点的有效个数
			int tmp3=b-l[t2]+1;
			if (t2==t1)		//如果a,b是同一个点,为特殊情况,答案b-a+1
			printf("%d\n",b-a+1);
		else
			printf("%d\n",max(tmp1,max(tmp2,tmp3)));

		} 
			
			
	}   
    
    
    return 0;
}

    原文作者:游程编码问题
    原文地址: https://blog.csdn.net/viphong/article/details/48219159
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞