http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23846
本题数据下,ST表和线段树都是100+ms 差别不大
题目大意:
给一个非降序排列的整数数组a,你的任务是对于一系列询问(i, j),回答ai,ai+1...aj中次数出现最多的值所出现的次数。
预处理是先把所有相同的元素合并成一个node,node含该元素编号+该元素个数 ( 称为表2)
并且记录好位置i对应的是预处理后的第i个node
对每次查询(a,b)
只需要把a,b位置对应的 表2 中的编号之间的所有 node ,对这些node的元素个数求一个RMQ,记为tmp1
然后a对应的node 的右端点-a+1 ,记为tmp2 (即元素值为a的可计算的个数)
同理 b对应的node b-左端点+1 ,记为tmp3 (即元素值为b的可计算的个数)
三者取最大即可
特殊情况,当a,b对应的node为同一个,那么只需要 输出b-a+1即可
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
#include <iostream>
using namespace std;
const int maxn=100005;
int ok;//ok个不同值的点
int value [maxn],cun[maxn];//第i点的值,以及相同的个数
int l[maxn],r[maxn];//第i个点的值在原序列中的左端点右端点
int who[maxn];//标明这位置属于第i点的管辖
int tm[maxn]; //原始数组
int mx[maxn][16];//16开logn就好了,st表
int max(int a,int b)
{
if (a<b)
return b;
return a;
}
void rmq_init()
{
int i,j;
for(j=1;j<=ok;j++) mx[j][0]=cun[j];
int m=floor(log((double)ok)/log(2.0));
for(i=1;i<=m;i++){
for(j=ok;j>0;j--){
mx[j][i]=mx[j][i-1];
if(j+(1<<(i-1))<=ok) mx[j][i]=max(mx[j][i],mx[j+(1<<(i-1))][i-1]);
}
}
}
int rmq_max(int l,int r)
{
int m=floor(log((double)(r-l+1))/log(2.0));
int a=max(mx[l][m],mx[r-(1<<m)+1][m]);
return a; //a为最大值
}
int main()
{
int t;
int n,m;
while (cin>>n)
{
if (!n) break;
scanf("%d",&m);
memset(mx,0,sizeof(mx));
int i;
for( i = 1; i <= n; i++)
{
scanf("%d",&tm[i]);
}
ok=0;
for( i = 1; i <= n; i++)
{
value[++ok]=tm[i];
cun[ok]=1;
who[i]=ok;
l[ok]=i;
while(tm[i+1]==tm[i])
{
cun[ok]++;
i++;
who[i]=ok;
}
r[ok]=i;
}
rmq_init();
int a,b;
for( i = 1; i <= m; i++)
{
scanf("%d%d",&a,&b);
int t1=who[a]; //t为a位置对应点的编号
int t2=who[b];
int tmp1=0;
if (t2>t1+1) //如果距离大于1 中间部分所有点的最大值作为比较参数,否则为0
tmp1=rmq_max(t1+1,t2-1);
int tmp2=r[t1]-a+1;//a点的有效个数
int tmp3=b-l[t2]+1;
if (t2==t1) //如果a,b是同一个点,为特殊情况,答案b-a+1
printf("%d\n",b-a+1);
else
printf("%d\n",max(tmp1,max(tmp2,tmp3)));
}
}
return 0;
}