首页 > 代码库 > UVA 11235 - Frequent values(RMQ)

UVA 11235 - Frequent values(RMQ)

UVA 11235 - Frequent values

题目链接

题意:给定一个升序数列,每次询问一个区间[l, r],求出其中相同数字最大的个数

思路:RMQ,由于是升序,所以数字大小相同的必然连在一块,先预处理出一共有多少段,每段包含多少个数字,和原数组中每个位置对应哪一段,最左边位置和最右边位置,然后每次询问的时候,可以把询问[L, R]的时候可以分成三段:
1、L到r[L]为一段,个数为R[L] - L + 1
2、l[R]到R为一段,个数为R - l[R] + 1
3、中间所有为一段,这一段就可以用RMQ求解,以个数为值
最后三段中个数较大的就是答案了
注意判断所选[L,R]只有1段和2段的情况
代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100005;

int n, q, a[N], l[N], r[N], num[N], cnt[N], v, rmq[N][20];

void init() {
    v = 0; int count, pre;
    scanf("%d", &q);
    for (int i = 0; i < n; i++) {
	scanf("%d", &a[i]);
	if (!i || a[i] != a[i - 1]) {
	    pre = i;
	    if (i)
		cnt[v++] = count;
	    count = 0;
	}
	count++;
	num[i] = v;
	l[i] = pre;
    }
    cnt[v++] = count;
    for (int i = n - 1; i >= 0; i--) {
	if (i == n - 1 || a[i] != a[i + 1]) {
	    pre = i;
	}
	r[i] = pre;
    }
}

void Build_RMQ(int* a, int n) {
    for (int i = 0; i < n; i++) rmq[i][0] = a[i];
    for (int j = 1; (1<<j) <= n; j++) {
	for (int i = 0; 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) {
    if (l > r) return 0;
    int k = 0;
    while ((1<<(k + 1)) <= r - l + 1) k++;
    return max(rmq[l][k], rmq[r - (1<<k) + 1][k]);
}

void solve() {
    Build_RMQ(cnt, v);
    int L, R;
    while (q--) {
	scanf("%d%d", &L, &R);
	L--; R--;
	if (num[L] == num[R]) printf("%d\n", R - L + 1);
	else printf("%d\n", max(Query(num[L] + 1, num[R] - 1), max(r[L] - L + 1, R - l[R] + 1)));
    }
}

int main() {
    while (~scanf("%d", &n) && n) {
	init();
	solve();
    }
    return 0;
}