BZOJ 4241: 历史研究 回滚莫队

4241: 历史研究

Time Limit: 80 Sec  Memory Limit: 512 MB
Submit: 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

Sample Output

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

猜你喜欢

转载自blog.csdn.net/blackjack_/article/details/79849999