|
题目链接:http://poj.org/problem?id=3368
 /**//*
题意:
给定一个长度为N(N <= 100000)的单调不降数列Si,然后是Q(Q <= 100000)条询问
,问给定区间出现最多的数的次数。

解法:
离散化+线段树 或者 离散化+RMQ

思路:
由于m很大,询问的复杂度必须要log(n),这样一来就先确定下来是线段树了,这个
题目有个限制条件,所有数都是单调不增的排列的,换言之,就是说如果两个数相同的话
,他们之间的所有数必定也和它们相同。
于是就有了mlog(n)的算法:
对于所有的数均设定一个组号,也可以叫离散化吧,相同的数有相同的组号,然后将各个
数的频率统计后记录在一个数组中,表示该类数的大小,对于输入的询问[x, y],直接查
询它们在哪个组,分三种情况讨论:
1. 如果x和y在一个组,那么最长长度就是y - x + 1
2. 如果组号相差1,那么找出两者的分界点z(假设z点和x点组号相同),那么答案就是Max
{z - x + 1, y - z}
3. 如果相差大于1,那么先将两头截掉,统计大的记录,再和中间那段的最大值比较大小,
中间那段的最大值可以用线段树或者RMQ区间查询最值。
*/

#include <iostream>

using namespace std;

#define maxn 100010
typedef int Tree_Index;

 struct Tree {
int Max;
}T[maxn*4];

 struct Pair {
int val;
int cnt;
}Pr[maxn];

int PrSize = 0;
int x[maxn], sum[maxn], pos[maxn];
int n, m;

 void Build(int p, int l, int r) {
 if(l == r) {
T[p].Max = Pr[l].cnt;
return ;
}
int mid = (l + r) >> 1;
Build(p<<1, l, mid);
Build(p<<1|1, mid+1, r);
T[p].Max = T[p<<1].Max > T[p<<1|1].Max ? T[p<<1].Max : T[p<<1|1].Max;
}

 Tree_Index Query(int p, int l, int r, int a, int b) {
 if(l == a && b == r) {
return p;
}
int mid = (l + r) >> 1;
 if(b <= mid) {
return Query(p<<1, l, mid, a, b);
 }else if(mid + 1 <= a) {
return Query(p<<1|1, mid+1, r, a, b);
 }else {
Tree_Index p1 = Query(p<<1, l, mid, a, mid);
Tree_Index p2 = Query(p<<1|1, mid+1, r, mid+1, b);
return T[p1].Max > T[p2].Max ? p1 : p2;
}
}

 void ProcessPr() {
int i, j;
PrSize = 0;
 for(i = 1; i <= n; i++) {
 if(x[i] == x[i-1]) {
Pr[PrSize].cnt++;
 }else {
PrSize++;
Pr[PrSize].val = x[i];
Pr[PrSize].cnt = 1;
}
}
 for(i = 1; i <= n; i++) {
sum[i] = Pr[i].cnt + sum[i-1];
for(j = sum[i-1]+1; j <= sum[i]; j++)
pos[j] = i;
}
}

 int findPos(int v) {
int l = 0;
int r = PrSize;
int ans = -1;
 while(l <= r) {
int m = (l + r) >> 1;
 if(v > sum[m]) {
l = m + 1;
if(m > ans)
ans = m;
}else
r = m - 1;
}
return ans + 1;
}

 int main() {
int i;
x[0] = INT_MIN;
 while(scanf("%d", &n) != EOF && n) {
scanf("%d", &m);
 for(i = 1; i <= n; i++) {
scanf("%d", &x[i]);
}
ProcessPr();
Build(1, 1, PrSize);
 while(m--) {
int x, y, l, r;
scanf("%d %d", &x, &y);
l = pos[x]; // findPos(x);
r = pos[y]; // findPos(y);
 if(l == r) {
printf("%d\n", y - x + 1);
 }else {
int ans = (sum[l] - x + 1) > (y - sum[r-1]) ? (sum[l] - x + 1) : (y - sum[r-1]);
 if(l + 1 < r) {
Tree_Index p = Query(1, 1, PrSize, l+1, r-1);
if(T[p].Max > ans)
ans = T[p].Max;
}
printf("%d\n", ans);
}
}
}
return 0;
}
|