学习笔记:莫队算法

暴力,因分块而优雅,因莫队而芳华。

形式

对于序列上的区间询问问题,如果从 \([l,r]\) 的答案能够 \(O(1)\) 扩展到 \([l,r+1]\)\([l,r-1]\)\([l-1,r]\)\([l+1,r]\)(即与 \([l,r]\) 相邻的区间)的答案,那么可以在 \(O(n\sqrt n)\) 的复杂度内求出所有询问的答案。

实现

离线后排序,顺序处理每个询问,暴力从上一个区间的答案转移到下一个区间答案(一步一步移动即可)。

排序方法

对于区间 \([l,r]\), 以 \(l\) 所在块的编号为第一关键字,\(r\) 为第二关键字从小到大排序。

复杂度分析

待补

例题 P2709 小B的询问

传送门:例题
莫队例题,对于询问区间,考虑能否 \(O(1)\) 扩展到相邻区间,答案是显然可以。某一个颜色的加减不影响到其它颜色,对于一种颜色 \(col_i\),多一个对答案贡献增加 \(2\times col_i + 1\),少一个答案贡献减少 \(2\times col_i - 1\)
使用莫队即可,时间复杂度 \(O(n\sqrt n)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 400000 + 10;
struct node
{
	int l,r,id;
} q[N];
int n,m,k,res,block,l = 1,r;
int ans[N],spl[N],L[N],R[N],cnt[N],col[N];
bool cmp(node aa,node bb)
{
	if(spl[aa.l] == spl[bb.l]) return aa.r < bb.r;
	else return spl[aa.l] < spl[bb.l];
}
void modify(int x,int val)
{
	if(col[x] > k) return ;
	res += 2 * val * cnt[col[x]] + 1;
	cnt[col[x]] += val;
}
signed main()
{
	scanf("%lld%lld%lld",&n,&m,&k);
	for(int i = 1;i <= n;i++) scanf("%lld",&col[i]);
	block = sqrt(n);
	for(int i = 1;i <= block;i++)
	{
		L[i] = (i - 1) * block + 1;
		R[i] = i * block;
	}
	if(R[block] < n) block++,L[block] = R[block - 1] + 1,R[block] = n;
	for(int i = 1;i <= block;i++)
	    for(int j = L[i];j <= R[i];j++)
	        spl[j] = i;
	for(int i = 1;i <= m;i++)
	{
		scanf("%lld%lld",&q[i].l,&q[i].r);
		q[i].id = i;
	}
	sort(q + 1,q + m + 1,cmp);
	for(int i = 1;i <= m;i++)
	{
		while(l > q[i].l) modify(--l,1);
		while(r < q[i].r) modify(++r,1);
		while(l < q[i].l) modify(l++,-1);
		while(r > q[i].r) modify(r--,-1);
		ans[q[i].id] = res;
	}
	for(int i = 1;i <= m;i++) printf("%lld\n",ans[i]);
	return 0;
}

普通莫队优化——奇偶化排序

奇偶化排序即对于属于奇数块的询问,\(r\) 按从小到大排序,对于属于偶数块的排序,\(r\) 从大到小排序,这样我们的 \(r\) 指针在处理完这个奇数块的问题后,将在返回的途中处理偶数块的问题,再向 \(n\) 移动处理下一个奇数块的问题,优化了 \(r\) 指针的移动次数,一般情况下,这种优化能让程序快 \(30\%\) 左右。

bool cmp(node aa,node bb)
{
	if(spl[aa.l] != spl[bb.l]) return spl[aa.l] < spl[bb.l];
	if(spl[aa.l] & 1) return aa.r < bb.r;
        else return aa.r > bb.r;
}
posted @ 2021-12-13 15:55  一程山雪  阅读(60)  评论(0)    收藏  举报