题目大意:
给出一个非降序排列的整数数组a1,a2,a3,...an,你的任务是对于一系列询问(i,j),回答a[i],a[i+1],...a[j]中出现次数最多的值所出现的次数。
解题思路:
整个数组是非降序的,所有相等元素都会聚集到一起。这样就可以把整个数组进行游程编码,把整个数组分成若干段,用sum[i]表示第i段的数出现的次数,num[p],lft[p],rig[p],分别表示位置p所在段的编号和左右端点的位置。每次查询(L,R)的结果为以下3个部分的最大值:
- 从L到L所在段的右端点的元素个数(即rig[L]-L+1)
- 从R所在段的左端点到R的元素个数(即R-lft[R]+1)
- 中间第num[L]+1段到第num[R]-1段的sum的最小值
特殊情况,如果L和R在同一段中,则答案是R-L+1。
AC代码:
- 解法一:线段树
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define io ios::sync_with_stdio(0),cin.tie(0)
#define ms(arr) memset(arr,0,sizeof(arr))
#define inf 0x3f3f3f
typedef long long ll;
typedef unsigned long long ULL;
const int mod=1e9+7;
const int maxn=1e5+7;
int n,q,lft[maxn],rig[maxn],num[maxn];
int cnt,sum[maxn],a[maxn];
struct tree
{
int L,R;
int data;
}tr[maxn<<2];
void build(int l,int r,int i)
{
tr[i].L=l;
tr[i].R=r;
if(l==r)
{
tr[i].data=sum[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,i<<1);
build(mid+1,r,i<<1|1);
tr[i].data=max(tr[i<<1].data,tr[i<<1|1].data);
}
int query(int l,int r,int i)
{
if(l>r)
return 0;
if(tr[i].L>=l&&tr[i].R<=r)
return tr[i].data;
int mid=(tr[i].L+tr[i].R)>>1;
if(l>mid)
return query(l,r,i<<1|1);//完全在右孩子区间
if(r<=mid)
return query(l,r,i<<1);//完全在左孩子区间
return max(query(l,r,i<<1),query(l,r,i<<1|1));
}
int main()
{
while(cin>>n&&n)
{
ms(sum);
cnt=0;
cin>>q;
a[0]=inf;
for(int i=1;i<=n;i++)
{
cin>>a[i];
num[i]=a[i]==a[i-1]?cnt:++cnt;
sum[cnt]++;
if(a[i]==a[i-1]) lft[i]=lft[i-1];
else lft[i]=i;
}
rig[n]=n;
for(int i=n-1;i>=1;i--)
{
if(a[i]==a[i+1]) rig[i]=rig[i+1];
else rig[i]=i;
}
build(1,cnt,1);
while(q--)
{
int l,r;
cin>>l>>r;
if(num[l]==num[r])
{
cout<<r-l+1<<endl;
continue;
}
int L=num[l]+1;
int R=num[r]-1;
int x=rig[l]-l+1;
int y=r-lft[r]+1;
int z=query(L,R,1);
int ans=max(max(x,y),z);
cout<<ans<<endl;
}
}
return 0;
}
- 解法二:RMQ
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define io ios::sync_with_stdio(0),cin.tie(0)
#define ms(arr) memset(arr,0,sizeof(arr))
#define mc(a,b) memcpy(a,b,sizeof(b))
#define inf 0x3f3f3f
#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
typedef long long ll;
typedef unsigned long long ULL;
const int mod=1e9+7;
const int N=1e5+7;
int n,q;
int arr[N],num[N],lef[N],righ[N],sum[N];
int d[N][100];
void init_RMQ(int len)
{
for(int i=1;i<=len;i++) d[i][0]=sum[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int query_RMQ(int l,int r)
{
if(l>r) return 0;
int k=0;
while((1<<(k+1))<=r-l+1) k++;
return max(d[l][k],d[r-(1<<k)+1][k]);
}
int main()
{
// fin;
while(cin>>n&&n){
memset(sum,0,sizeof(sum));
int cnt=0;
cin>>q;
arr[0]=inf;
for(int i=1;i<=n;i++){
cin>>arr[i];
num[i]=arr[i]==arr[i-1]?cnt:++cnt;
sum[cnt]++;
if(arr[i]==arr[i-1]) lef[i]=lef[i-1];
else lef[i]=i;
}
righ[n]=n;
for(int i=n-1;i>0;i--){
if(arr[i]==arr[i+1]) righ[i]=righ[i+1];
else righ[i]=i;
}
init_RMQ(cnt);
int l,r;
while(q--)
{
cin>>l>>r;
int ans;
if(num[l]==num[r]) ans=r-l+1;
else{
int x=righ[l]-l+1;
int y=r-lef[r]+1;
int z=query_RMQ(num[l]+1,num[r]-1);
ans=max(max(x,y),z);
}
cout<<ans<<endl;
}
}
return 0;
}