|
題目鏈接: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;
}
|