POJ 3368 RMQ - ST

//找序列 [a,b]之间出现频率最多的数,输出频率
//因为是有序序列所以,可以转化成RMQ,w[i] = num[i]累计出现次数
//然后找 [a,b]之间最大的w[i]就可以了
//考虑开头的情况,用st[i]存第一个num[i]的位置,ed[st[i]]存最后一个位置
//答案就是 max( w[ed[st[a]]] - w[a], rmqmax( ed[st[a]] + 1, b ) );
//注意下 ed[st[a]] 有没有超过b就可以了

//ST模板是百度百科的 =。=
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>

#define MN 100005
using namespace std;
//17 MN <= 2^17
int mi[MN][18],mx[MN][18],num[MN],w[MN], st[MN], ed[MN];
int n,q;
int a,b;
int LOG[MN];
void rmqinit()
{
	int i,j,m;
	for(i=1;i<=n;i++){mi[i][0]=mx[i][0]=w[i];}
	m=floor(log((double)n)/log(2.0));
	for(i=1;i<=m;i++)
	{
		for(j=n;j>=1;j--)
		{
			mx[j][i]=mx[j][i-1];
			if(j+(1<<(i-1))<=n)mx[j][i]=max(mx[j][i],mx[j+(1<<(i-1))][i-1]);
			mi[j][i]=mi[j][i-1];
			if(j+(1<<(i-1)<=n))mi[j][i]=min(mi[j][i],mi[j+(1<<(i-1))][i-1]);
		}
	}
}
int rmqmin(int l,int r)
{
	int m= LOG[r-l+1];
	return min(mi[l][m],mi[r-(1<<m)+1][m]);
}
int rmqmax(int l,int r)
{
	int m=LOG[r-l+1];
	return max(mx[l][m],mx[r-(1<<m)+1][m]);
} 

int main()
{

	for( int i = 1;i < MN;i++ )
		LOG[i] = floor( log( ( double )i ) / log( 2.0 )) ;
	
	while( scanf( "%d",&n ) && n !=0 )
	{
		scanf( "%d%d",&q,num+1 );
		w[1] = st[1] = 1;
		for( int i = 2;i <= n;i++ )
		{
			scanf( "%d",num+i );
			if( num[i] == num[i-1] ) 
			{
				w[i] = w[i-1] + 1;
				st[i] = st[i-1];
			}
			else 
			{
				ed[st[i-1]] = i-1;
				w[i] = 1;
				st[i] = i;
			}
		}

		ed[st[n]] = n;

		rmqinit();

		for( int i = 1;i <= q;i++ )
		{
			scanf( "%d%d",&a,&b );

			int mxx = w[ed[st[a]]] - w[a] + 1;
			
			if( ed[st[a]] >= b )
			{
				mxx = w[b] - w[a] + 1;	
			}
			else
			{
				int mxxx;
				if( mxx < ( mxxx = rmqmax( ed[st[a]] + 1, b ) ) ) mxx = mxxx;
			}
			printf( "%d\n",mxx );
		}
	}
	return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值