莫队算法基础与练习

莫队算法

gym卡了莫队,于是趁这个机会学一下莫队

莫队的核心是分块排序,这种特殊的排序方法将任务按排序后的顺序完成,可以在解决绝大多数无修改的离线区间问题中极大的优化时间(优化了sqrt ( n )左右)。

Sona

NBUT - 1457

题意:n个数,寻问10000次,任意区间内的相等数的次数的立方和。

题解:将n个数离散化后,用莫队将询问分块排序,暴力计算出答案,在按原顺序输出结果。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;

ll n,a[100007],t,head,maze,size,ak[100007],num[100007],ans[100007],b[100007];
struct madoka{
	ll l;
	ll r;
	ll p;
}ma[100007];
long long int qpow(long long int x,long long int n)
{
    long long int res=1;
	while(n>0)
	{
	   if(n%2==1)	
	   {
	   	 res=res*x;
	   	 res=res;
	   }
	   x=x*x;
	   x=x;
	   n>>=1;
	}
	return res;	
}
bool cmp(madoka a1,madoka a2){
	if(ak[a1.l]==ak[a2.l]){
		return a1.r<a2.r;
	}
	return ak[a1.l]<ak[a2.l];
}
void go(){
	ll l=1,r=1,ansn=1;
	num[a[1]]++;
	for(int i=1;i<=t;i++){
		while(r<ma[i].r){
			r++;
			ansn-=qpow(num[a[r]],3);
			num[a[r]]++;
			ansn+=qpow(num[a[r]],3);
		}
		while(l>ma[i].l){
			l--;
			ansn-=qpow(num[a[l]],3);
			num[a[l]]++;
			ansn+=qpow(num[a[l]],3);
		}
		while(r>ma[i].r){
			ansn-=qpow(num[a[r]],3);
			num[a[r]]--;
			ansn+=qpow(num[a[r]],3);
			r--;
		}
		while(l<ma[i].l){
			ansn-=qpow(num[a[l]],3);
			num[a[l]]--;
			ansn+=qpow(num[a[l]],3);
			l++;
		}
		ans[ma[i].p]=ansn;
	}
}
int main(){
	while(scanf("%lld",&n)!=EOF){
		memset(num,0,sizeof(num));
		size=(ll)sqrt(n*1.0);
		maze=ceil((double)n/size);
		head=1;
		for(int i=1;i<=maze;i++){
			for(int j=head;j<head+size&&j<=n;j++){
				ak[j]=i;
			}
			head+=size;
		}
		int m=0;
		for(int i=1;i<=n;++i)
	    {
	    	scanf("%lld",&a[i]);
		    b[++m]=a[i];
	    }
    	sort(b+1,b+1+m);
    	m=unique(b+1,b+1+m)-b-1;
    	for(int i=1;i<=n;++i)
    		a[i]=lower_bound(b+1,b+1+m,a[i])-b;
		scanf("%lld",&t);
		for(int i=1;i<=t;i++){
			scanf("%lld%lld",&ma[i].l,&ma[i].r);
			ma[i].p=i;
		}
		sort(ma+1,ma+1+t,cmp);
		go();
		for(int i=1;i<=t;i++){
			printf("%lld
",ans[i]);
		}
	}
	//return 0;
} 

Little Elephant and Array

CodeForces - 220B

题意:n个数,寻问10000次,任意区间内的相等数的次数与其数相等的个数。

题解:与上题差不多,但有个坑要注意下,离散化后会导致值改变,所以某数的次数要与它离散化前比较,之后便是莫队板子。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

int n,m,t,a[100007],b[100007],num[100007],size,maze,head,ak[100007],ans[100007];

struct madoka{
	int l;
	int r;
	int p;
}ma[100007];

bool cmp(madoka a1,madoka a2){
	if(ak[a1.l]==ak[a2.l]){
		return a1.r<a2.r;
	}
	return ak[a1.l]<ak[a2.l];
}

void go(){
	int l=2,r=1,ansn=0;
	for(int i=1;i<=t;i++){
		while(r<ma[i].r){
			r++;
			if(num[a[r]]==b[a[r]]){
				ansn--;
			}
			num[a[r]]++;
			if(num[a[r]]==b[a[r]]){
				ansn++;
			}
		}
		while(r>ma[i].r){
			if(num[a[r]]==b[a[r]]){
				ansn--;
			}
			num[a[r]]--;
			if(num[a[r]]==b[a[r]]){
				ansn++;
			}
			r--;
		}
		while(l>ma[i].l){
			l--;
			if(num[a[l]]==b[a[l]]){
				ansn--;
			}
			num[a[l]]++;
			if(num[a[l]]==b[a[l]]){
				ansn++;
			}
		}
		while(l<ma[i].l){
			if(num[a[l]]==b[a[l]]){
				ansn--;
			}
			num[a[l]]--;
			if(num[a[l]]==b[a[l]]){
				ansn++;
			}
			l++;
		}
		ans[ma[i].p]=ansn;
	}
	
}

int main(){
	scanf("%d%d",&n,&t);
	size=sqrt(n);
	maze=ceil((double)n/size);
	head=1;
	for(int i=1;i<=maze;i++){
		for(int j=head;j<head+size&&j<=n;j++){
			ak[j]=i;
		}
		head+=size;
	}
	int m=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[++m]=a[i];
	}
	sort(b+1,b+1+m);
	m=unique(b+1,b+1+m)-b-1;
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+1+m,a[i])-b;
	}
	for(int i=1;i<=t;i++){
		scanf("%d%d",&ma[i].l,&ma[i].r);
		ma[i].p=i;
		
	}
	sort(ma+1,ma+1+t,cmp);
	
	go();
	for(int i=1;i<=t;i++){
		printf("%d
",ans[i]);
	}
}

Machine Learning

CodeForces - 940F

题意:给一个长度n数组,a数组记录值,q次操作,两种操作,一种修改a+p位置的值,一种算 l , r 区间的值的个数的mex(mex指,如果有s个相等的数,那s是好的,然后你要输出最小的不好的。如mex=3,说明区间内有相等的数的个数为1的存在,为2的存在,为3的不存在)。

题解:传送门

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

int n,q,ans[200007],a[200007],b[200007],l,r,z,size,head,maze,ak[200007],num[200007],cnt[200007];
vector<int>lsh,qans;

struct madoka{
	int l;
	int r;
	int p;
}ho[200007],lin;
vector<madoka>ma;

bool cmp(madoka a1,madoka a2){
	if(ak[a1.l]==ak[a2.l]){
		if(ak[a1.r]==ak[a2.r]){
			return a1.p<a2.p;
		}
		return ak[a1.r]<ak[a2.r];
	}
	return ak[a1.l]<ak[a2.l];
}

void dis(){
	sort(lsh.begin(),lsh.end());
	lsh.erase(unique(lsh.begin(),lsh.end()),lsh.end());
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(lsh.begin(),lsh.end(),a[i])-lsh.begin()+1;
	}
	for(int i=1;i<=q;i++){
		if(ho[i].p!=0){
			ho[i].l=lower_bound(lsh.begin(),lsh.end(),ho[i].l)-lsh.begin()+1;
			ho[i].r=lower_bound(lsh.begin(),lsh.end(),ho[i].r)-lsh.begin()+1;
		}
	}
}

void go(){
	l=1,r=1;
	int p=0;
	cnt[num[a[r]]]--;
	num[a[r]]++;
	cnt[num[a[r]]]++;
	for(int i=0;i<ma.size();i++){
		while(r<ma[i].r){
			r++;
			cnt[num[a[r]]]--;
			num[a[r]]++;
			cnt[num[a[r]]]++;
		}
		while(r>ma[i].r){
			cnt[num[a[r]]]--;
			num[a[r]]--;
			cnt[num[a[r]]]++;
			r--;
		}
		while(l<ma[i].l){
			cnt[num[a[l]]]--;
			num[a[l]]--;
			cnt[num[a[l]]]++;
			l++;
		}
		while(l>ma[i].l){
			l--;
			cnt[num[a[l]]]--;
			num[a[l]]++;
			cnt[num[a[l]]]++;
		}
		while(p<ma[i].p){
			p++;
			if(ho[p].p==0)continue;
			if(ma[i].l<=ho[p].p&&ma[i].r>=ho[p].p){
				cnt[num[ho[p].l]]--;
				num[ho[p].l]--;
				cnt[num[ho[p].l]]++;
				cnt[num[ho[p].r]]--;
				num[ho[p].r]++;
				cnt[num[ho[p].r]]++;
			}
			a[ho[p].p]=ho[p].r;
		}
		while(p>ma[i].p){
			if(ho[p].p==0){
				p--;
				continue;
			}
			if(ma[i].l<=ho[p].p&&ma[i].r>=ho[p].p){
				cnt[num[ho[p].l]]--;
				num[ho[p].l]++;
				cnt[num[ho[p].l]]++;
				cnt[num[ho[p].r]]--;
				num[ho[p].r]--;
				cnt[num[ho[p].r]]++;
			}
			a[ho[p].p]=ho[p].l;
			p--;
		}
		for(int j=1;j<=n;j++){
			if(cnt[j]==0){
				ans[ma[i].p]=j;
				break;
			}
		}
	}
}

int main(){
	scanf("%d%d",&n,&q);
	size=(int)pow(n,2.0/3.0);
	maze=ceil((double)n/size);
	for(int i=1;i<=maze;i++){
		for(int j=head;j<head+size&&j<=n;j++){
			ak[j]=i;
		}
		head+=size;
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
		lsh.push_back(a[i]);
	}
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&z,&l,&r);
		if(z==1){
			lin.l=l;
			lin.r=r;
			lin.p=i;
			ma.push_back(lin);
			qans.push_back(i);
		}
		else{
			lin.l=a[l];
			lin.r=r;
			lin.p=l;
			ho[i]=lin;
			a[l]=r;
			lsh.push_back(r);
		}
	}
	for(int i=1;i<=n;i++)a[i]=b[i];
	dis();
	sort(ma.begin(),ma.end(),cmp);
	go();
	for(int i=0;i<qans.size();i++){
		printf("%d
",ans[qans[i]]);
	}
}
原文地址:https://www.cnblogs.com/whitelily/p/13194854.html