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; }