Description
IOI國曆史研究的第一人——JOI教授,最近獲得了一份被認爲是古代IOI國的住民寫下的日記。JOI教授爲了通過這份日記來研究古代IOI國的生活,開始着手調查日記中記載的事件。
日記中記錄了連續N天發生的時間,大約每天發生一件。
事件有種類之分。第i天(1<=i<=N)發生的事件的種類用一個整數Xi表示,Xi越大,事件的規模就越大。
JOI教授決定用如下的方法分析這些日記:
- 選擇日記中連續的一些天作爲分析的時間段
- 事件種類t的重要度爲t*(這段時間內重要度爲t的事件數)
- 計算出所有事件種類的重要度,輸出其中的最大值
現在你被要求製作一個幫助教授分析的程序,每次給出分析的區間,你需要輸出重要度的最大值。
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
Sample Output
9
8
8
16
16
HINT
1<=N<=10^5
1<=Q<=10^5
1<=Xi<=10^9 (1<=i<=N)
Source
JOI 2013~2014 春季training合宿 競技1 By PoPoQQQ
Solution
-
題意 : 多次詢問區間中的 每個數*其出現次數 的最大值。
-
我們可以離散化後做莫隊,但是普通莫隊是不可行的,因爲刪去最大值我們並不知道次大值。
-
這是我們需要稍作修改——回滾莫隊!
-
同樣將詢問區間按左端點所屬塊爲第一關鍵字、右端點爲第二關鍵字從小到大排,
-
每次我們將左指針置於塊的最右端,每次重新移動即可。
-
若詢問的區間在同一塊內就 暴力統計。
-
總時間複雜度是 的。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=1e5+5;
struct data
{
int l,r,id;
}c[N];
LL sum;
int a[N],b[N],bel[N],t[N],cnt[N];
LL ans[N];
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline bool cmp(data x,data y)
{
return bel[x.l]<bel[y.l] || bel[x.l]==bel[y.l] && x.r<y.r;
}
inline LL max(LL x,LL y)
{
return x>y?x:y;
}
inline int min(int x,int y)
{
return x<y?x:y;
}
inline void add(int x)
{
cnt[a[x]]++;
sum=max(sum,(LL)cnt[a[x]]*b[a[x]]);
}
inline void del(int x)
{
cnt[a[x]]--;
}
int main()
{
int n=read(),q=read();
int size=sqrt(n);
for(int i=1;i<=n;i++)
{
a[i]=b[i]=read();
bel[i]=(i-1)/size+1;
}
sort(b+1,b+1+n);
b[0]=unique(b+1,b+1+n)-(b+1);
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+b[0],a[i])-b;
for(int i=1;i<=q;i++) c[i].l=read(),c[i].r=read(),c[i].id=i;
sort(c+1,c+1+q,cmp);
for(int i=1,j=1;i<=n;i+=size)
{
sum=0;
int up=min(n,i+size-1);
int l=up+1,r=up;
memset(cnt,0,sizeof(cnt));
while(j<=q && bel[i]==bel[c[j].l])
{
if(bel[c[j].l]==bel[c[j].r])
{
LL val=0;
for(int k=c[j].l;k<=c[j].r;k++) t[a[k]]=0;
for(int k=c[j].l;k<=c[j].r;k++)
{
t[a[k]]++;
val=max(val,(LL)t[a[k]]*b[a[k]]);
}
ans[c[j].id]=val;
j++;
continue;
}
while(r<c[j].r) add(++r);
LL val=sum;
while(l>c[j].l) add(--l);
ans[c[j].id]=sum;
while(l<=up) del(l++);
sum=val;
j++;
}
}
for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
return 0;
}