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; }