洛谷P5906 【模板】回滚莫队&不删除莫队

https://www.luogu.com.cn/problem/P5906

莫队好多套路啊。。。建议都学习一下

学习自题解https://www.luogu.com.cn/problem/solution/P5906

回滚莫队的意思大概就是,按l所在块再求枚举询问,相同的一起求答案,l部分的必须每次从当前块的最右边向左拓展到想要的地方,求完当前询问之后,你此时更新出的答案要回滚到l向左移动之前,再求下个询问。

左端点在一个块中的询问处理完之后,我们清空所有最左和最右的数字位置的数组,再处理下个块中的询问。

这样,对于同一个块,右端点是不断增加的,所以当前块右边的ed是不变的,当前块内的数字的ed有可能新出现,就先标记上,然后回退的时候再清掉。

那么一个询问最多就是l移动sqrt(n)次,对于同一个块内所有询问,r最多移动n次,总复杂度还是nsqrt(n)

#include<bits/stdc++.h>
using namespace std;

const int maxl=2e5+10;

int n,m,len,bn,tot;
int a[maxl],num[maxl],ans[maxl];
int bel[maxl],last[maxl],st[maxl],ed[maxl],clr[maxl];
struct que
{
	int l,r,id;
	inline bool operator < (const que &b)const
	{
		return (bel[l]!=bel[b.l])?bel[l]<bel[b.l]:r<b.r;
	}
}q[maxl];

inline void prework()
{
	scanf("%d",&n);
	len=sqrt(n);
	for(int i=1;i<=n;i++)
	{	
		scanf("%d",&a[i]);
		bel[i]=(i-1)/len+1;num[i]=a[i];
	}
	bn=bel[n];
	sort(num+1,num+1+n);
	tot=unique(num+1,num+1+n)-num-1;
	for(int i=1;i<=n;i++)
		a[i]=lower_bound(num+1,num+1+tot,a[i])-num;
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].id=i;
	}
	sort(q+1,q+1+m);
}

inline int bf(int l,int r)
{
	int mx=0;
	for(int i=l;i<=r;i++)
		last[a[i]]=0;
	for(int i=l;i<=r;i++)
	if(!last[a[i]])
		last[a[i]]=i;
	else
		mx=max(mx,i-last[a[i]]);
	return mx;
}

inline void mainwork()
{
	int ind=1,br,l,r,now,cnt,tmp;
	for(int j=1;j<=bn;j++)
	{
		br=min(n,j*len),l=br+1;r=l-1;
		cnt=0;now=0;
		while(bel[q[ind].l]==j)
		{
			if(bel[q[ind].r]==j)
			{	
				ans[q[ind].id]=bf(q[ind].l,q[ind].r);
				ind++;
				continue;
			}
			while(r<q[ind].r)
			{
				r++;
				ed[a[r]]=r;
				if(!st[a[r]])
					st[a[r]]=r,clr[++cnt]=a[r];
				now=max(now,r-st[a[r]]);
			}
			tmp=now;
			while(l>q[ind].l)
			{
				l--;
				if(ed[a[l]])
					now=max(now,ed[a[l]]-l);
				else
					ed[a[l]]=l;
			}
			ans[q[ind].id]=now;
			while(l<=br)
			{
				if(ed[a[l]]==l)
					ed[a[l]]=0;
				l++;
			}
			now=tmp;
			++ind;
		}
		for(int i=1;i<=cnt;i++)
			st[clr[i]]=ed[clr[i]]=0;
	}
}

inline void print()
{
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/109127796