莫队

莫队与分块一样,都是一种优化时间复杂度的思想方法,它的应用十分广。

莫队分三种:普通莫队、树上莫队和带修莫队。

  • 普通莫队

莫队的实质就是通过分块和排序来提高效率。

分块就不讲了。还是和平常一样块大小为\sqrt{n},块的个数也是\sqrt{n}

关键的是排序。排序方式如下:同一块的按r从小到大排,不同块的按l从小到大排。(其实就是先按块的顺序排,同一块的再按r排)。

贴一下代码,方便理解:

int cmp(const data &a,const data &b)
{
	if(a.be==b.be)
	{
		if(a.r<b.r)return 1;
		else return 0;
	}
	else
	{
		if(a.l<b.l)return 1;
		else return 0;
	}
}

排好序之后,我们这样来求答案:对于每一块的开头,我们暴力求出l~r的答案。然后对于同块的接下来的l、r,我们暴力移动左右端点更新答案就好了。

到这里我们来分析一下时间复杂度,这里我们分类讨论一下:

  1. 首先对于每一块开头暴力求l~r的答案,每一次求最多是O(n)的,因为最多有\sqrt{n}快,所以这个的时间复杂度是O(n\sqrt{n})的。
  2. 然后就是暴力移动r,因为同一块的r是已经排好序了,所以同一块中r最多移动n次,而一共有\sqrt{n}块,所以这个的时间复杂度也是O(n\sqrt{n})的。
  3. 最后是每次移动l,这个就很显然了。因为同一块中每次移动l最多移动\sqrt{n}距离,而最多移动\sqrt{n}次,所以时间复杂度是O(n)的。

到这里,我们就可以得出结论了:莫队的时间复杂度不是O(n^{2})的,而是O(n\sqrt{n})的。这是一个优秀的做法。

 

  • 树上莫队

如果我们现在要查询树上的一条链的答案,那么该怎么做呢?

首先我们要知道一个叫欧拉序的东西(也叫括号序)。

我们dfs一遍,每次dfs到一个点时就把这个点加入队列,dfs完这个点的子树时又把它加入队列。dfs完整棵树后我们就得到了一个长度为2n的队列。

然后记st[i]表示i点第一次出现的位置,ed[i]表示i点第二次出现的位置。接着我们就可以发现对于一组x、y(假设st[x]<=st[y]):

  1. 若x为lca,那么st[x]~st[y]中只出现一次的点就是我们要求的链
  2. 若x不为lca(y也不可能为lca),那么ed[x]~st[y]中只出现一次的点就是我们要求的链

这个画几个例子就明白了。不过当我们画出例子之后,就会发现我们这样做漏掉了一个点,这个点就是lca。不过没关系,最后补上lca就行了。

 

  • 带修莫队

 

带修莫队就是再加入一个tim作为第三关键字排序(当l和r都在同一块是才排tim)。tim表示的是当前询问实在第tim个修改结束之后才求答案的。排好序之后我们不单止要暴力移动l和r,还要暴力移动tim,这样就可以了。

时间复杂度:最坏情况O(n^{\frac{5}{3}})。

分析如下:我们这时只需要考虑tim的移动。和上面一样,只有当l、r都有序时tim的移动次数才是n的。在最坏情况下,假设每一个l后所有的块都被r占据了,那么总共l、r有序的有(n/L)^2个。每一个tim移动n次,那么总的时间复杂度就是\frac{n^{3}}{L^{2}}。当L=n^{\frac{2}{3}}时最小,最小为n^{\frac{5}{3}}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值