再搞一道RMQ吧。。
题意是 给出序列 非降序的 询问q i j 要i 和 j之间的 出现次数最多的次数 就是最高次数
n q 都是10w
这个题目啊我们用游程长度编码 把原来的数组分段
最近才在科学导论的数据压缩里看过的。。
value[i] 表示 第i断的值 count[i]表示第i断的值 出现的次数。
num[p]位置p所在断的编号
left[p]表示位置p所在断的起点
right[p]表示位置p所在断的终点
我们对于每个查询 L R
把L R 分成三段 求这三段的最大次数
第一个是从L开始到这个段的终点的次数 right[L]-L+1
第二个是最后半段 就是 R-left[R]+1
终点那个就是完整的断了 也即是rmq问题 num[L]+1 断开始 到 num[R]-1 这些段的count的最大值。
代码还没写。。。今天肯定写好贴上来
开始写了 发现有些东西不太好处理。。
正好在12点前过了。。。
wa了一次 因为忽略了 l和 r在一个断的情况。
#include<iostream>
#include<cstdio>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int maxn=100005;
int arr[maxn];//存这个数组
int value[maxn];// 存每一段的值
int Count[maxn];// 存每一段那个值一共出现的次数
int num[maxn];//从 原来下标i在第几个断
int Left[maxn];// 存原来下标i在的那个断的 左端点
int Right[maxn];// 存原来那个下标i在的那个断的右端点
int n,q,k;
int d[maxn][20];
void rmq_init()
{
int i,j;
for(i=1;i<=k;++i)
d[i][0]=Count[i];
for(j=1;(1<<j)<=k;++j)
{
for(i=1;i+(1<<(j-1))<=k;++i)
{
d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
}
}
int rmq_query(int l,int r)
{
int kk=0;
while((1<<(kk+1))<=r-l+1)
kk++;
return max(d[l][kk],d[r-(1<<kk)+1][kk]);
}
int main()
{
int i,j;
while(scanf("%d",&n),n)
{
memset(Count,0,sizeof(Count));
memset(Left,0,sizeof(Left));
memset(Right,0,sizeof(Right));
scanf("%d",&q);
for(i=1;i<=n;++i)//先把这个数组输进来
scanf("%d",&arr[i]);
k=0;
arr[0]=arr[1]+1;//让数组中第一个元素 和左边的不相等。
for(i=1;i<=n;++i)
{
if(arr[i]==arr[i-1])
Count[k]++;
else//开始新的一段
{
k++;
value[k]=arr[i];
Count[k]++;
Left[i]=i;
Right[i-1]=i-1;
}
num[i]=k;//这个时候i的断肯定是k
}
//已测试过 到这里 value数组 和count数组已经搞定了 从1到k 一共k断。
//接下来得搞定num left right 三个数组了
Right[n]=n;
int L,R;
for(i=1;i<=n;++i)
{
if(!Left[i])
Left[i]=L;
else
L=Left[i];
}
for(i=n;i>=0;--i)
{
if(!Right[i])
Right[i]=R;
else
R=Right[i];
}
/*
for(i=1;i<=n;++i)
{
printf("%d %d %d %d %d\n",value[i],Count[i],num[i],Left[i],Right[i]);
}*/
//搞定初始化数组的问题
rmq_init();
int ans;
for(i=0;i<q;++i)
{
scanf("%d %d",&L,&R);
if(num[L]==num[R])
ans=R-L+1;
else
ans=max(Right[L]-L+1,R-Left[R]+1);
if(num[R]-1>=num[L]+1)
ans=max(ans,rmq_query(num[L]+1,num[R]-1));
printf("%d\n",ans);
}
}
return 0;
}