4241: 历史研究
Time Limit: 80 Sec Memory Limit: 512 MBSubmit: 1514 Solved: 461
[Submit][Status][Discuss]
Description
IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记。JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件。
日记中记录了连续N天发生的时间,大约每天发生一件。
事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。
JOI教授决定用如下的方法分析这些日记:
1. 选择日记中连续的一些天作为分析的时间段
2. 事件种类t的重要度为t*(这段时间内重要度为t的事件数)
3. 计算出所有事件种类的重要度,输出其中的最大值
现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。
Input
第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
接下来一行N个空格分隔的整数X1...XN,Xi表示第i天发生的事件的种类
接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。
Output
输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度
Sample Input
5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
Sample Output
9
8
8
16
16
8
8
16
16
HINT
1<=N<=10^5
1<=Q<=10^5
1<=Xi<=10^9 (1<=i<=N)
Source
回滚莫队。
这个题 n sqrt(n) logn 很好想
但是这个复杂度比较丑
我们考虑若只有加入或删除一种操作(虽然这样是做梦) 那么就不需要数据结构的log
但是我们可以trick一下 进行把删除搞掉
具体来讲
考虑莫队算法将询问排序之后 对于左端点所在块相同的询问 右端点是单调递增的
所以固定一个区间在询问左端点所在块的块尾
对于每次询问 左端点只移动sqrt(n)个 右端点递增即可 每当左端点换块就重置
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef double db;
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=10*x+ch-'0';ch=getchar();}
return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}
const int N=100100;
int n,Q;
struct point
{
int val,pos;
friend bool operator <(const point &x,const point &y)
{return x.val<y.val;}
}p[N];
int block,bel[N];
struct query
{
int l,r,pos;
friend bool operator <(const query &x,const query &y)
{return bel[x.l]==bel[y.l] ? x.r<y.r : bel[x.l]<bel[y.l];}
}q[N];
int a[N],V[N];
int cnt[N];
ll ans[N];
void solve()
{
register int i,j,l,r;
ll mx(0);
for(i=1;i<=Q;++i)
{
if(bel[q[i].l]!=bel[q[i-1].l])
{
mx=0,
r=bel[q[i].l]*block;
memset(cnt,0,sizeof(cnt));
}
if(bel[q[i].l]==bel[q[i].r])
{
for(j=q[i].l;j<=q[i].r;++j) cnt[a[j]]++,mx=max(mx,1ll*cnt[a[j]]*V[a[j]]);
for(j=q[i].l;j<=q[i].r;++j) cnt[a[j]]--;
ans[q[i].pos]=mx;mx=0;
continue;
}
while(r<q[i].r)
r++,cnt[a[r]]++,mx=max(mx,1ll*cnt[a[r]]*V[a[r]]);
ll pre=mx;
l=bel[q[i].l]*block;
while(l>=q[i].l)
cnt[a[l]]++,mx=max(mx,1ll*cnt[a[l]]*V[a[l]]),l--;
while(l<bel[q[i].l]*block) l++,cnt[a[l]]--;
ans[q[i].pos]=mx;
mx=pre;
}
}
int main()
{
n=read(),Q=read();
block=floor(sqrt(n));
register int i,j,tot(1);
for(i=1;i<=n;++i) p[i].val=read(),p[i].pos=i;
sort(p+1,p+1+n);
V[1]=p[1].val,a[p[1].pos]=1;
for(i=2;i<=n;++i)
{
if(p[i].val!=p[i-1].val) tot++,V[tot]=p[i].val;
a[p[i].pos]=tot;
}
for(i=j=tot=1;i<=n;++i,++j)
{
bel[i]=tot;
if(j==block) tot++,j=0;
}
for(i=1;i<=Q;++i) q[i].l=read(),q[i].r=read(),q[i].pos=i;
sort(q+1,q+Q+1);
solve();
for(i=1;i<=Q;++i)
printf("%lld\n",ans[i]);
return 0;
}