对应HDU题目:点击打开链接
Description
You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i andj (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.
Input
The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line contains nintegers a1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}) separated by spaces. You can assume that for each i ∈ {1, ..., n-1}: ai ≤ ai+1. The following q lines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the
query.
The last test case is followed by a line containing a single 0.
Output
For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.
Sample Input
10 3 -1 -1 1 1 1 1 3 10 10 10 2 3 1 10 5 10 0
Sample Output
1 4 3
题意:求某区间内众数的个数
/* 1 2 3 4 5 6 7 8 9 10 -1 -1 1 1 1 1 3 10 10 10 因为是非递减,故可以这样处理: -1 -1 为一块,即fa[ 1~2 ]=1; 1 1 1 1 为一块,即fa[ 3~6 ]=2; 3 为一块,即fa[7]=3; 10 10 10 为一块,即fa[ 8~10 ]=4; 设询问范围为(l,r) 1.如果fa[l]==fa[r],结果直接就是r-l+1; 2.如果fa[r]-fa[l]==1,表示区域相邻,就分别求右边区域个数跟左边区域个数,取大值 3.如果fa[r]-fa[l]>1,表示区域相差不少于1个,就分别求最右边区域个数,最左边区域个数跟中间区域个数中的最大值,取大值 */ #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> using namespace std; const int MAXN=100000+10; const int INF=1<<30; int fa[MAXN]; int dp[MAXN][20]; //dp[i][j]表示从第i个数起连续2^j个数的最大值 int n,m,u,maxn; struct Block { int num,left,right,count; }block[MAXN]; void input() { u=1; int x; scanf("%d", &x); int front=x; //这块区域的数是front fa[1]=u; //第一个数属于第一块区域(这里u==1) block[u].num=x; //第一个数是什么 block[u].left=1; //第一块区域最左边是从1开始 block[u].count=1; //第一块区域有多少个数 for(int i=2; i<=n; i++){ scanf("%d", &x); if(x==front){ //x还是属于这块区域 block[u].count++; fa[i]=u; //第i个数属于第u块区域 } else{ //x不属于这块区域 block[u].right=i-1; //u区域最右边是第i-1个数 block[++u].left=i; //新区域最左边是第i个数 block[u].num=x; block[u].count=1; front=x; fa[i]=u; } } block[u].right=n; //最后一个区域最右边的数是第n个数 } void caldp() { for(int i=1; i<=u; i++){ dp[i][0]=block[i].count; } for(int j=1; j<=20; j++){ //注意这个要在外层 for(int i=1; i<=u; i++){ if(i+(1<<j)-1 <= u){ dp[i][j]=max(dp[i][j-1], dp[i+(1<<(j-1))][j-1]); } } } } int rmq(int l, int r) { int k=log(double(r-l+1))/log(2.0); return max(dp[l][k], dp[r-(1<<k)+1][k]); } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d", &n,&m), n) { memset(dp,0,sizeof(dp)); input(); caldp(); while(m--) { int l,r; scanf("%d%d", &l,&r); if(fa[r]==fa[l]){ //属于同一区域 printf("%d\n", r-l+1); continue; } if(fa[r]-fa[l]==1){ //区域相邻 int rr=r-block[fa[r]].left+1; //右区域个数 int ll=block[fa[l]].right-l+1; //左区域个数 printf("%d\n", rr>ll?rr:ll); //取大的那边 continue; } //相隔不小于一个区域 int L=fa[l], R=fa[r]; //L,R分别为左边和右边那块区域 int rr=r-block[R].left+1; int ll=block[L].right-l+1; maxn=rmq(L+1, R-1); //中间那些区域的最大值 //比较三者取最大值 int M=rr>ll?rr:ll; M=M>maxn?M:maxn; printf("%d\n", M); } } return 0; }