题目大意
给定一个长度为
题解
看见这种xjb询问的题当然是要下意识地用分块来搞一搞的,又因为只有询问,且题目没有要求强制在线,所以就可以理所应当地“分块+莫队”来搞这道题了。
对于这道题,莫队的加入操作是很好实现的,只要增加一下被加入区间的权值的出现次数并同时更新一下答案就可以了,但是删除操作却很难实现,因为删除操作后无法O(1)地更新答案。这时一位id为alone_wolf的神犇为我提供了一个思路:实现没有删除操作,只有加入操作的回滚式莫队算法。
回滚式莫队是以询问的左端点所在的块为第一关键字,右端点为第二关键字对询问进行排序的。考虑枚举每一个块,枚举这个块时处理左端点在这个块内的所有询问。因为对于左端点在相同块内的询问,其右端点一定是递增的(因为就是这么排序的)。
对于询问的右端点和左端点在同一块内的,询问的大小一定小于
对于其余的询问,因为右端点是单调向右的,所以不会出现左右摆动的情况,因此对于当前块右端点右边的部分只要单调地加入就可以了,因为只会单调地加入元素,所以这部分的总时间复杂度为
时间复杂度
代码
/**************************************************************
Problem: 4241
User: CHN
Language: C++
Result: Accepted
Time:9968 ms
Memory:5592 kb
****************************************************************/
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
register int val=0; char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9')); val=ch-'0';
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+ch-'0';
return val;
}
const int maxn=int(1e5)+111;
int n,m;
int a[maxn], b[maxn], v[maxn];
int siz, num, bel[maxn];
long long ans[maxn];
struct Q {
int l,r,id;
bool operator < (const Q &b) const {
return bel[l]==bel[b.l]?r<b.r:bel[l]<bel[b.l];
}
}q[maxn];
void Read() {
register int i;
n=read(), m=read();
for(i=1;i<=n;++i)
v[i]=a[i]=read();
sort(v+1,v+1+n);
int nn=unique(v+1,v+1+n)-(v+1);
for(i=1;i<=n;++i)
b[i]=lower_bound(v+1,v+1+nn,a[i])-v;
for(i=1;i<=m;++i) {
q[i].l=read(), q[i].r=read();
q[i].id=i;
}
while(siz*siz<n) ++siz;
for(i=1;i<=n;++i)
bel[i]=(i-1)/siz+1, num=max(num,bel[i]);
sort(q+1,q+1+m);
return;
}
long long tmp=0;
int cnt[maxn];
void Add(int id) {
++cnt[b[id]];
tmp=max(tmp,1ll*cnt[b[id]]*a[id]);
}
void Del(int id) {
--cnt[b[id]];
}
long long small(int l,int r) {
static int cnt2[maxn];
long long res=0;
register int i;
for(i=l;i<=r;++i)
cnt2[b[i]]=0;
for(i=l;i<=r;++i) {
++cnt2[b[i]];
res=max(res,1ll*cnt2[b[i]]*a[i]);
}
return res;
}
int Mo(int pos,int id) {
int L=min(id*siz,n);
register int i=pos,j, ql=L+1, qr=ql-1;
for(j=1;j<=n;++j) cnt[j]=0;
tmp=0;
for(;bel[q[i].l]==id;++i) {
if(bel[q[i].l]==bel[q[i].r]) {
ans[q[i].id]=small(q[i].l,q[i].r);
continue;
}
while(qr<q[i].r) Add(++qr);
long long cur=tmp;
while(ql>q[i].l) Add(--ql);
ans[q[i].id]=tmp;
while(ql<L+1) Del(ql++);
tmp=cur;
}
return i;
}
void Solve() {
register int i,pos=1;
for(i=1;i<=num;++i)
pos=Mo(pos,i);
return;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
Read();
Solve();
for(int i=1;i<=m;++i)
printf("%lld\n",ans[i]);
return 0;
}