问题 E: 简单的RMQ
时间限制: 2 Sec 内存限制: 64 MB
提交: 914 解决: 158
[提交][状态][讨论版]
题目描述
给定一个数组,其中的元素满足非递减顺序。任意给定一个区间[i,j],求其中某个元素重复出现的最大次数。
输入
多组数据输入。每组数据的第一行包含两个整数n和q(1<=n,q<=100000),下一行包含n个整数a1,…,an(-100000<=ai<=100000,i∈{1,…,n}),用空格分隔,数列是升序的(ai<=ai+1)。接下来的q行,每行包含两个整数i和j(1<=i<=j<=n),表示给定区间[i,j]。
输入结束于0(自成一行)。
输出
对输入的q个区间,每个区间输出一个整数表示该区间内重复最多的元素出现的次数,用换行分隔。
样例输入
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
样例输出
1
4
3
题解:先预处理出每段的长度和结束的点,建线段树维护最大值,对于每次询问l,r。先暴力找到结束点,得到ll rr,然后判断大小即可。(这SB写法都能过?数据是有多水。。。下面有优化)
代码;
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<string.h>
//#define ll long long
using namespace std;
const int N=1e5+10;
const int mod=1e7+9;
int n,q,l,r;
int a[N];
int sum[N<<2];
void pushup(int rt)
{
sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}
void update(int l,int r,int pos,int val,int rt)
{
if(l==r)
{
sum[rt]=val;
return ;
}
int mid=(r+l)>>1;
if(pos<=mid)
update(l,mid,pos,val,rt<<1);
if(pos>mid)
update(mid+1,r,pos,val,rt<<1|1);
pushup(rt);
}
int query(int l,int r,int ll,int rr,int rt)
{
if(ll<=l&&rr>=r)
{
return sum[rt];
}
int mid=(r+l)>>1;
int ans=1;
if(ll<=mid)
{
ans=max(ans,query(l,mid,ll,rr,rt<<1));
}
if(rr>mid)
{
ans=max(ans,query(mid+1,r,ll,rr,rt<<1|1));
}
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
if(n==0) break;
memset(sum,0,sizeof(sum));
scanf("%d",&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int ans=1;
int tmp=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]!=tmp)
{
update(1,n,i-1,ans,1);
ans=1;
tmp=a[i];
}
else
{
ans++;
}
}
while(q--)
{
scanf("%d%d",&l,&r);
if(a[l]==a[r])
{
printf("%d\n",r-l+1);
}
else
{
int mx=1;
ans=0;
tmp=a[l];
int ll,rr;
for(int i=l+1;i<=r;i++)
{
if(a[i]!=tmp)
{
ans=max(ans,mx);
ll=i;
break;
}
else
mx++;
}
tmp=a[r];
mx=1;
for(int i=r-1;i>=l;i--)
{
if(a[i]!=tmp)
{
ans=max(ans,mx);
rr=i;
break;
}
else
mx++;
}
ans=max(ans,query(1,n,ll,rr,1));
printf("%d\n",ans);
}
}
}
}
很明显,上面SB写法最坏时间复杂度为o(qn)这复杂度过个p题啊。改法:对于找边界,我们不要暴力,而是将每段的边界先预处理出来,然后直接判断就好。
代码:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<string.h>
//#define ll long long
using namespace std;
const int N=1e5+10;
const int mod=1e7+9;
int n,q,l,r;
int a[N];
int sum[N<<2];
int belong[N];
int L[N],R[N];
void pushup(int rt)
{
sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}
void update(int l,int r,int pos,int val,int rt)
{
if(l==r)
{
sum[rt]=val;
return ;
}
int mid=(r+l)>>1;
if(pos<=mid)
update(l,mid,pos,val,rt<<1);
if(pos>mid)
update(mid+1,r,pos,val,rt<<1|1);
pushup(rt);
}
int query(int l,int r,int ll,int rr,int rt)
{
if(ll<=l&&rr>=r)
{
return sum[rt];
}
int mid=(r+l)>>1;
int ans=1;
if(ll<=mid)
{
ans=max(ans,query(l,mid,ll,rr,rt<<1));
}
if(rr>mid)
{
ans=max(ans,query(mid+1,r,ll,rr,rt<<1|1));
}
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
if(n==0) break;
memset(sum,0,sizeof(sum));
scanf("%d",&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int ans=1;
int tmp=a[1];
int cnt=1;
L[cnt]=1;
belong[1]=cnt;
for(int i=2;i<=n;i++)
{
if(a[i]!=tmp)
{
R[cnt]=i-1;
cnt++;
L[cnt]=i;
belong[i]=cnt;
update(1,n,i-1,ans,1);
ans=1;
tmp=a[i];
}
else
{
belong[i]=cnt;
ans++;
}
}
while(q--)
{
scanf("%d%d",&l,&r);
if(a[l]==a[r])
{
printf("%d\n",r-l+1);
}
else
{
ans=0;
ans=max(ans,R[belong[l]]-l+1);
ans=max(ans,r-L[belong[r]]+1);
ans=max(ans,query(1,n,R[belong[l]]+1,L[belong[r]]-1,1));
printf("%d\n",ans);
}
}
}
}