当遇到大量的区间询问时,假如区间的左右下标有着一定的规律,我们可以如何求解?
如:
[ 1 , 3 ] , [ 1 , 4 ] , [ 1 , 5 ] , [ 2 , 5 ] [1,3],[1,4],[1,5],[2,5] [1,3],[1,4],[1,5],[2,5]。
当然是双指针!其时间复杂度从 n 2 n^2 n2下降到 o ( n ) o(n) o(n)。
莫队就是这样一个算法,通过预处理询问顺序,来降低时间复杂度,当然,前提是能够预处理,强制在线的题目便与莫队无缘。
其预处理流程如下:
- 首先将数据分块,分块大小为size
- 将区间排序,如果区间的左端点落在同一个块中,那么我们将其按右端点大小排序。
- 如果它们的左端点不在同一块中,那么便按照左端点升序排序。
当我们处理完区间顺序之后,剩下的就是之后双指针的左右移动罢了,考虑增加和删除对与答案的影响,也就结束了。
ll sum = 0;
s[a[1]]++;
for (int i = 1; i <= m; i++)
{
while (l < q[i].l)sum += del(l++);
while (l > q[i].l)sum += add(--l);
while (r < q[i].r)sum += add(++r);
while (r > q[i].r)sum += del(r--);
ans[q[i].id] = sum;
}
那么问题来了,如何分析莫队算法的时间复杂度呢?
考虑对单一块进行询问,我们考虑最糟糕的情况,同一块中的左端点再反复横跳,先是再块的最左端,然后跑到最右端如此反复,当然,右端点是有序的,它只会后移操作。那么其实时间复杂度为 o ( s i z e ∗ m i + n ) o(\sqrt{size}*m_i+n) o(size∗mi+n),其中 m i m_i mi表示再第i块中的区间数.
那么对于总体的时间复杂度为 o ( s i z e ∗ m + n ∗ ( n s i z e ) ) o(\sqrt{size}*m+n*(\frac{n}{size})) o(size∗m+n∗(sizen))。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 5e4 + 5;
struct node {
int l, r, id;
}q[maxn];
ll n, m, a[maxn], ans[maxn], l = 1, r = 1, sum, s[maxn], id[maxn], Size;
ll lef[maxn], righ[maxn];
bool cmp(struct node x, struct node y)
{
if (id[x.l] == id[y.l])
{
if(id[x.l]&1)return x.r < y.r;
return x.r>y.r;
}//排序,左端点在同一块内,按右区间升序排序 ,奇数偶数优化
return x.l < y.l;//否则,按左区间排序
}
ll add(int x)
{
ll gs = ++s[a[x]];
return s[a[x]] * (s[a[x]] - 1) / 2 - (s[a[x]] - 1)*(s[a[x]] - 2) / 2;//返回影响
}
ll del(int x)
{
ll gs = --s[a[x]];
return gs * (gs - 1) / 2 - gs * (gs + 1) / 2;//返回影响
}
ll gcd(ll a, ll b)
{
if (a == 0)return b>0?b:1;
return b == 0 ? a : gcd(b, a%b);
}
int main()
{
ios::sync_with_stdio(false);
//freopen("P1494_1.in", "r+", stdin);
cin >> n >> m;
Size = n / sqrt(m * 2 / 3);//分块大小,会影响时间复杂度。
for (int i = 1; i <= n; i++)
{
cin >> a[i];
id[i] = (i - 1) / Size + 1;
}
for (int i = 1; i <= m; i++)
{
cin >> q[i].l >> q[i].r;
q[i].id = i;
lef[i] = q[i].l;
righ[i] = q[i].r;
}
sort(q + 1, q + m + 1, cmp);
ll sum = 0;
s[a[1]]++;
for (int i = 1; i <= m; i++)
{
while (l < q[i].l)sum += del(l++);
while