莫队与分块精简小结

我觉得我还要补上带修莫队,树上莫队等等……(先咕着……)

分块:引用范围广,实现简洁(注意块的边界)一般为\(\sqrt{n}\)分块。

块中可维护很多东西,维护信息时从后往前处理。

例题:\(HNOI2010\)弹飞绵羊

#include<bits/stdc++.h>
using namespace std;
#define S(x) ((x)*(x))
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=2e5+10;
int n,m,Cnt,Siz;
int K[N],Typ[N],Tim[N],End[N];
struct Lump{int l,r;} Lum[N];
inline void Prepare(int l,int r)
{
	for(int i=r;i>=l;i--)
		if(i+K[i]>=Lum[Typ[i]].r) Tim[i]=1,End[i]=i+K[i];
		else Tim[i]=Tim[i+K[i]]+1,End[i]=End[i+K[i]];
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
	n=read(),Siz=sqrt(n);
	for(int i=1;i<=n;i++) K[i]=read();
	for(int i=1;i<=n&&i+Siz-1<=n;i+=Siz) Lum[++Cnt].l=i,Lum[Cnt].r=i+Siz-1;
	if(Lum[Cnt].r<n) Lum[++Cnt].l=Lum[Cnt-1].r+1,Lum[Cnt].r=n;Cnt=1;
	for(int i=1;i<=n;i++) Cnt+=(i>Lum[Cnt].r),Typ[i]=Cnt;
	Prepare(1,n);m=read();
	while(m--)
	{
		int C=read(),j=read()+1,k;
		if(C==1)
		{
			int ans=Tim[j],Now=End[j];
			while(Now<=n)
				ans+=Tim[Now],Now=End[Now];
			printf("%d\n",ans);
		}
		else k=read(),K[j]=k,Prepare(Lum[Typ[j]].l,Lum[Typ[j]].r);
	}
}

莫队:带有分块思想的优化暴力。

例题:\(SP3267D-query\)

考虑一个优化:用两个指针移动,来计算答案,指针移动到和询问重合时记录答案。

优化操作代码:(\(Sum\)为不同元素个数,\(Tag\)为记录的桶,\(Num\)为元素类型)

while(l<p[i].l) Sum-=(!(--Tag[Num[l++]]));
while(l>p[i].l) Sum+=(!(Tag[Num[--l]]++));
while(r<p[i].r) Sum+=(!(Tag[Num[++r]]++));
while(r>p[i].r) Sum-=(!(--Tag[Num[r--]]));

但是这样仍然会被卡死,考虑对询问排序。如果是一般的排序,显然还是会导致被卡。

如何写\(Cmp\),我们可以对\(1\sim n\)分块,如果两个区间左端点在同一个块内,按右端点排序,如不在,按左端点在的块排序。复杂度不会证……这是一个讲的较好的详解

有一个小小的常数优化,就是分奇偶性排序,左端点在同一个奇数块中,按右端点从小到大排,在同一个偶数块中,按右端点从大到小排序,不在同一个块中按块排序。

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=1e6+10;
//map<int,int> Tag;
struct Region{int l,r,Id;} p[N];
int n,m,Siz,Cnt,Sum,Num[N],Typ[N],ans[N],Tag[N];
inline bool Cmp(Region x,Region y) {return (Typ[x.l]^Typ[y.l])?Typ[x.l]<Typ[y.l]:((Typ[x.l]&1)?x.r<y.r:x.r>y.r);}
int main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
	n=read();Siz=sqrt(n);
	for(int i=1;i<=n;i++) Num[i]=read(),Typ[i]=(i-1)/Siz+1;
	int l=1,r=0;m=read();
	for(int i=1;i<=m;i++) p[i].l=read(),p[i].r=read(),p[i].Id=i;
	sort(p+1,p+m+1,Cmp);
	for(int i=1;i<=m;i++)
	{
		while(l<p[i].l) Sum-=(!(--Tag[Num[l++]]));
		while(l>p[i].l) Sum+=(!(Tag[Num[--l]]++));
		while(r<p[i].r) Sum+=(!(Tag[Num[++r]]++));
		while(r>p[i].r) Sum-=(!(--Tag[Num[r--]]));
		ans[p[i].Id]=Sum;
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
posted @ 2019-10-20 21:51  风骨傲天  阅读(245)  评论(0编辑  收藏  举报