uva11235(RMQ问题)

   题目的意思是:有一个有序的数组,然后每次给出数组的两个端点L,R,要求出数组区间[L,R]里面出现最多的数字。

   题目的解法:运用RMQ的思想求解即可,在求解之前需要转化一下模型,我们把这个数组可以转化为对于数字p,记录它的左端点位置nL[p],右端点位置nR[p],个数nV[p],对于每一次访问实际我们可以分三块来进行求解:首先是左端点num[L]的数字个数等于nR[num[L]] - L + 1,右端点的num[R]的数字个数等于R - nL[num[R]] + 1,然后中间的数字结果就用RMQ进行求解。

   RMQ求解的主要代码块:  

  for(int i = 0; i < cN; i ++) A[i][0] = nV[num2[i]];
  for(int j = 1; (1 << j) <= cN; j ++){    
    for(int i = 0; i + (1 << j) <= cN; i ++){
	A[i][j] = max(A[i][j-1], A[i+(1 << (j - 1))][j - 1]);
    }
  }
  <pre name="code" class="cpp">  ans = nR[num1[L]] - L + 1;
  ans = max(R - nL[num1[R]] + 1, ans);
  L = p[num1[L]] + 1, R = p[num1[R]] - 1;
  if(L <= R){
    int k = 0;
    while((1 << (k + 1)) <= R - L + 1) k ++;
    ans = max(ans, A[L][k]);
    ans = max(ans, A[R + 1 - (1 << k)][k]);
  }

      

    

#include "stdio.h"
#include "string.h"
#include "math.h"
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;

#define MAXM 1
#define MAXN 1
#define max(a,b) a > b ? a : b
#define min(a,b) a < b ? a : b
#define Mem(a,b) memset(a,b,sizeof(a))
int Mod = 1000000007;
double pi = acos(-1.0);
double eps = 1e-6;

typedef struct{
	int f,t,w,next;
}Edge;
Edge edge[MAXM];
int head[MAXN];
int kNum;
typedef long long LL;

void addEdge(int f, int t, int w)
{
	edge[kNum].f = f;
	edge[kNum].t = t;
	edge[kNum].w = w;
	edge[kNum].next = head[f];
	head[f] = kNum ++;
}

map<int,int> nL, nR, nV;
map<int,int> p;
int n, cN, q;
int A[100005][20];
int num1[100005];
int num2[100005];

void solve(){
	cin>>q;

	for(int i = 0; i < n; i ++){
		scanf("%d", &num1[i]);
	}

	nL.clear(), nR.clear(), nV.clear();
	p.clear(), cN = 0;
	Mem(A, 0);

	int flag = false, pre = -1;
	nL[num1[0]] = 1;
	p[num1[0]] = cN ++;
	num2[0] = num1[0];
	for(int i = 1; i < n; i ++){
		if(num1[i] != num1[i-1]){
			nR[num1[i-1]] = i - 1;
			nV[num1[i-1]] = nR[num1[i-1]] - nL[num1[i-1]] + 1;
			//pre = num1[i];
			num2[cN] = num1[i];
			nL[num1[i]] = i;
			p[num1[i]] = cN ++;
			//flag = true;
		}
	}
	nR[num1[n-1]] = n - 1;
	nV[num1[n-1]] = nR[num1[n-1]] - nL[num1[n-1]] + 1;

	for(int i = 0; i < cN; i ++) A[i][0] = nV[num2[i]];
	for(int j = 1; (1 << j) <= cN; j ++){
		for(int i = 0; i + (1 << j) <= cN; i ++){
			A[i][j] = max(A[i][j-1], A[i+(1 << (j - 1))][j - 1]);
		}
	}
	
	int L, R, ans;
	for(int i = 0; i < q; i ++){
		scanf("%d %d",&L, &R);
		L -= 1, R -= 1;
		if(num1[L] == num1[R]){
			printf("%d\n", R - L + 1);
		}
		else{
			ans = nR[num1[L]] - L + 1;
			ans = max(R - nL[num1[R]] + 1, ans);
			L = p[num1[L]] + 1, R = p[num1[R]] - 1;
			if(L <= R){
				int k = 0;
				while((1 << (k + 1)) <= R - L + 1) k ++;
				ans = max(ans, A[L][k]);
				ans = max(ans, A[R + 1 - (1 << k)][k]);
			}
			printf("%d\n", ans);
		}
	}

}


int main()
{
//	freopen("d:\\test.txt", "r", stdin);
	while(cin>>n){
		if(n == 0) break;
		solve();
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值