题面传送门
看上去很玄学的亚子。
我们很容易发现,要想
r
p
rp
rp最大,要让每次取出的都是一个严格上升的序列,则原问题转换成最少取几次。
那么对于有
v
i
v_i
vi的一个数,一定要取
v
i
v_i
vi次才能取完。则答案为区间内最多的数。则变成了求区间众数。
那么可以用莫队求区间众数,开一个
f
i
f_i
fi数组记录
i
i
i这个数有几个,
s
i
s_i
si记录有
i
i
i个的数有几个,用二重辅助来求解。
代码实现:
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,k,ans[200039],l,r,f[200039],sf[200039],h[200039],a[200039],head;
struct yyy {
int x,y,num;
} fs[200039],s[200039];
inline void read(register int &x) {
x=0;register char s=getchar();
while(s<'0'||s>'9')s=getchar();
while(s>='0'&&s<='9')x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
inline void print(register int x) {
if(x<0) {putchar('-');print(-x);return;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline bool cmp1(yyy x,yyy y) {return x.x<y.x;}
inline bool cmp2(yyy x,yyy y) {return (h[x.x]==h[y.x])?((h[x.x]&1)?x.y<y.y:x.y>y.y):(x.x<y.x);}
int main() {
register int i,l,r,head=0;
scanf("%d%d",&n,&m);
k=sqrt(n);
for(i=1; i<k; i++) h[i]=1;
for(i=k; i<=n; i++) h[i]=h[i-k]+1;
for(i=1; i<=n; i++)read(a[i]),fs[i].x=a[i],fs[i].num=i;
sort(fs+1,fs+n+1,cmp1);
a[fs[1].num]=1;
for(i=2; i<=n; i++) {
if(fs[i].x==fs[i-1].x) a[fs[i].num]=a[fs[i-1].num];
else a[fs[i].num]=a[fs[i-1].num]+1;
}
for(i=1; i<=m; i++) read(s[i].x),read(s[i].y),s[i].num=i;
sort(s+1,s+m+1,cmp2);
l=1;r=0;
sf[0]=1e9;
for(i=1; i<=m; i++) {
while(l<s[i].x) {sf[--f[a[l]]]++;sf[f[a[l++]]+1]--;while(!sf[head])head--;}
while(r>s[i].y) {sf[--f[a[r]]]++;sf[f[a[r--]]+1]--;while(!sf[head])head--;}
while(l>s[i].x) {sf[++f[a[--l]]]++;sf[f[a[l]]-1]--;while(sf[head+1])head++;}
while(r<s[i].y) {sf[++f[a[++r]]]++;sf[f[a[r]]-1]--;while(sf[head+1])head++;}
ans[s[i].num]=-head;
}
for(i=1; i<=m; i++) print(ans[i]),putchar('\n');
}