正题
题目链接:https://www.luogu.com.cn/problem/AT1219
题目大意
nnn个数字,mmm次询问一个区间内ti∗it_i*iti∗i的最大值,tit_iti即区间内iii的出现次数。
解题思路
用回滚莫队的思想,对于在不同块中的询问,我们把左端点所在块的右端点作为分界点,显然以后所有与左端点在同一个块中的询问的右端点会单调上升,我们用指针维护这个答案和信息。
那在分界点左边的部分因为不会超过n\sqrt nn个,所以我们直接暴力搞就好了。
时间复杂度O(nn)O(n\sqrt n)O(nn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const ll N=1e5+10;
struct node{ll l,r,id;
}q[N];
ll n,m,T,a[N],b[N],v[N],pr[N],c[N];
bool cmp(node x,node y){if(x.l/T==y.l/T)return x.r<y.r;return x.l<y.l;
}
int main()
{scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i];sort(b+1,b+1+n);ll cnt=unique(b+1,b+1+n)-b-1;for(ll i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;T=sqrt(n);for(ll i=1;i<=m;i++){scanf("%lld%lld",&q[i].l,&q[i].r);q[i].id=i;}sort(q+1,q+1+m,cmp);q[0].l=-T;ll r=0,bf_ans=0;for(ll x=1;x<=m;x++){if(q[x].l/T==q[x].r/T){ll ans=0;for(ll i=q[x].l;i<=q[x].r;i++)v[a[i]]++,ans=max(ans,v[a[i]]*b[a[i]]);pr[q[x].id]=ans;for(ll i=q[x].l;i<=q[x].r;i++)v[a[i]]=0;q[x].l=q[x-1].l;continue;}int tail=q[x].l/T*T+T-1;if(q[x].l/T!=q[x-1].l/T){for(ll i=1;i<=cnt;i++)c[i]=0;bf_ans=0;r=tail;}while(r<q[x].r)c[a[++r]]++,bf_ans=max(bf_ans,c[a[r]]*b[a[r]]);ll ans=bf_ans;for(ll i=tail;i>=q[x].l;i--)v[a[i]]++,ans=max(ans,(c[a[i]]+v[a[i]])*b[a[i]]);for(ll i=tail;i>=q[x].l;i--)v[a[i]]=0;pr[q[x].id]=ans;}for(ll i=1;i<=m;i++)printf("%lld\n",pr[i]);return 0;
}