头疼
题意
给一个n长度的a int数组,且a数组为不下降数列,询问q次,每次询问l到r之间出现次数最多的数字出现了多少次。
IO
Input
The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line contains n integers a1 , … , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, …, n}) separated by spaces. You can assume that for each i ∈ {1, …, n-1}: ai ≤ ai+1. The following q lines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the
query.
The last test case is followed by a line containing a single 0.
Output
For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.
分析
一开始一看这题询问区间内值的分布情况,就想用主席树,结果到了询问的时候仔细想想又发现主席树破不了。
总是出现这样的问题就是过于注重分析如何维护数据结构保持consistant,而不认真地想想数据结构维护什么数据才能得到答案。
这题把问题转化成了RMQ问题,计算每个数值出现的次数,然后把这个数组按照数字出现的顺序排成一个新的数组,并且记录原数组中每个位置对应新数组中哪个位置,记录新数组每个数对应原数组的区间范围,由于是不下降数列,这些很自然。
然后线段树或者ST稀疏表维护RMQ信息,对于一次查询l,r,先修改l和r对应新数组位置的值,因为可能正好卡在一串相等数字的中间,然后查询对应区间的RMQ信息,再把信息改回来。
还有另一种办法是比较l位置和l位置值结束位置、r位置和r位置值开始位置、l值结束位置和r值开始位置之间的RMQ信息,这样就不需要更新操作。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MXN 100010
int da[MXN];
int n,q;
int a[MXN],st[MXN],ed[MXN],mp[MXN];
int cnt;
int ll[MXN<<2],rr[MXN<<2],mx[MXN<<2];
void build(int id,int l,int r){
ll[id]=l,rr[id]=r;
if(l==r){
mx[id]=da[l];
return;
}
int m=(l+r)>>1,ls=id<<1,rs=ls|1;
build(ls,l,m);
build(rs,m+1,r);
mx[id]=max(mx[ls],mx[rs]);
}
void update(int id,int loc,int num){
if(ll[id]==rr[id]){
mx[id]=num;
return;
}
int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
if(loc<=m) update(ls,loc,num);
else update(rs,loc,num);
mx[id]=max(mx[ls],mx[rs]);
}
int query(int id,int l,int r){
if(ll[id]==l&&rr[id]==r) return mx[id];
int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
if(r<=m) return query(ls,l,r);
else if(l>m) return query(rs,l,r);
else return max(query(ls,l,m),query(rs,m+1,r));
}
int main(){
while(scanf("%d",&n)!=EOF&&n){
scanf("%d",&q);
cnt=-1;
int pre=-1000000;
for(int i=1;i<=n;++i){
scanf("%d",a+i);
if(a[i]!=pre){
if(pre!=-1000000){
ed[cnt]=i-1;
}
++cnt;
da[cnt]=0;
st[cnt]=i;
pre=a[i];
}
mp[i]=cnt;
++da[cnt];
}
++cnt;
build(1,0,cnt-1);
for(int Q=0;Q<q;++Q){
int l,r;
scanf("%d%d",&l,&r);
int tl=mp[l],tr=mp[r];
if(tl==tr){
printf("%d\n",r-l+1);
continue;
}
update(1,tl,ed[tl]-l+1);
update(1,tr,r-st[tr]+1);
printf("%d\n",query(1,tl,tr));
update(1,tl,ed[tl]-st[tl]+1);
update(1,tr,ed[tr]-st[tr]+1);
}
}
return 0;
}