自从上次邀请赛之后说要学习莫队算法,一直拖到现在,💊总的来说,莫队算法是一种离线分块的算法,将总区间分成若干个块($\sqrt{n}$),然后对每一块更新查询$ans$的值。时间复杂度$O\ (n\sqrt{n})$
这里强烈安利一篇blog
SPOJ D-query
题意:给定一个长度为n序列,再给定m次查询,每次查询区间内出现元素的种类数
思路:听说可以主席树或者离线树状数组做,莫队算法的入门题,耗时270ms。将所有查询分成$\sqrt{n}$个块,再按照块排序,然后对于每个块可以利用之前算过的答案(即数量)来更新当前的答案(数量)。
1 |
|
codeforces-Powerful array
题意:给定n个元素序列,m次询问,要统计区间内[l,r]元素个数乘以元素的值的和$\sum_{l}^{r}cnt_i^2*i$,对于不同元素区间只计算一次。
思路:莫队算法,只需要修改del函数和add函数就行,在每次更新cnt前面,加上ans-=(1LL*a[p]*cnt[a[p]]*cnt[a[p]]);
,更新之后再加上ans+=(1LL*a[p]*cnt[a[p]]*cnt[a[p]]);
,注意不能把全部变量变成long long,会超时的😑。
1 |
|
区间求和
题意:给定$n$个元素,$m$次询问,求区间$[l\ ,\ r]$内$\sum_{i=l}^{r}{a_i * cnt_{a_i}}$
与上题不同的是,每个元素都要算到。
1 |
|
HDU-6534.Chika and Friendly Pairs
湘潭邀请赛C题,当时卡的题,现在补掉
题意:给定一个长度为$n$的序列,$m$次询问,一个数$k$。询问你在区间$[l\ ,\ r]$中,符合$|a_i-a_j|\leq k$并且$i < j$有多少对这样的数。
思路:莫队+树状数组+离散化,首先对于每次查询$a_i$,我只要查询区间内$[a_i-k\ ,\ a_i+k]$的种数即可,利用树状数组就行,然后由于序列中的数最大有$10^9$,而数的个数只有$27000$,就可以通过离散化将其缩小,再用莫队算法。
对于新加进来的数$a_i$,ans+=(query(up[l])-query(lowa[l]))
,然后再add(mida[l],1)
,仔细想想就会发现,如果你先写add函数,就会把本身的值也算进去。
对于去掉的数$a_i$,则需要先add(mida[l],-1)
,然后再更新ans,ans-=(query(up[l])-query(lowa[l]))
,因为query查询的时候会把mida[l]也计算进来。
离散化的模版
1 | //n 原数组大小 num 原数组中的元素 lsh 离散化的数组 cnt 离散化后的数组大小 |
该题ac的代码(390MS)
1 |
|