莫队从入门到弃坑
莫队算法是由前国家队队长莫涛提出的一种极其
玄学暴力的算法%%%,总结来说就是一个优雅的暴力双指针,配合上玄学的分块降低复杂度。
1、前置技能
1、基础的分块思想(sqrt分块)
2、重载sort排序
掌握以上两种就能解决一些简单的莫队问题,看起来很简单
3、LCA(暂时没学树上莫队,后面再补)
4、离散化(有时候需要对值域进行分块,需要离散化数值)
写这篇文章侧重总结自己练习出的问题,算法教学及复杂度证明由下面两篇大佬博客进行学习。
2、基础莫队
2.1HH的项链
传送门
Des
给你长度为n的数组,m个询问,每次询问[l, r]有多少个不同的数字
Solution
这题数据较强,正解是树状数组,但是这个题用于引入莫队十分不错,下面这个题是数据弱化版Go here
code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m;
int a[N], pos[N], ans[N], cnt;
map<int, int> mp;
struct qnode
{
int l, r, id;
} q[N];
void add(int n)
{
if(mp[a[n]]) mp[a[n]]++;
else
{
mp[a[n]] = 1;
cnt++;
}
}
void sub(int n)
{
mp[a[n]]--;
if(mp[a[n]] == 0) cnt--;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
int siz = sqrt(n);
for(int i = 1; i <= n; ++i)
{
cin >> a[i];
pos[i] = i / siz;
}
cin >> m;
for(int i = 1; i <= m; ++i)
{
cin >> q[i].l >> q[i].r;
q[i].id = i;
}
sort(q + 1, q + 1 + m, [](qnode x, qnode y)
{
return pos[x.l] == pos[y.l] ? x.r < y.r : pos[x.l] < pos[y.l];
});
int l = 1, r = 0;
for(int i = 1; i <= m; ++i)
{
while(q[i].l < l) add(--l);
while(q[i].r > r) add(++r);
while(q[i].l > l) sub(l++);
while(q[i].r < r) sub(r--);
ans[q[i].id] = cnt;
}
for(int i = 1; i <= m; ++i) cout << ans[i] << "\n";
return 0;
}
2.2Rmq Problem / mex
传送门
Solution
分块后,暴力查询,如果块中有空缺,即块中有val值未被填满,即是mex。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 100;
template <typename T> inline void read(T& t)
{
int f = 0, c = getchar();
t = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) t = t * 10 + c - 48, c = getchar();
if (f) t = -t;
}
int n, m, a[N], mp[N];
int val[N], cnt[N], L[N], R[N], pos[N], tot;
int ok[N];
struct qnode
{
int l, r, id;
} q[N];
bool cmp(qnode& a, qnode& b)
{
return (pos[a.l] == pos[b.l]) ? a.r < b.r : pos[a.l] < pos[b.l];
}
int Q()
{
int idx = 1;
while(val[idx] == R[idx] - L[idx] + 1) idx++;
for(int i = L[idx]; i <= R[idx]; ++i) if(!cnt[i]) return i;
}
void add(int x)
{
if(cnt[x] == 0) val[pos[x]]++;
cnt[x]++;
}
void sub(int x)
{
if(cnt[x] == 1) val[pos[x]]--;
cnt[x]--;
}
signed main()
{
read(n), read(m);
for(int i = 1; i <= n; ++i)
{
read(a[i]);
if(a[i] > n) a[i] = n + 1;
}
int siz = sqrt(n);
for(int i = 0; i <= n; ++i) pos[i] = i / siz + 1;
for(int i = 0; i <= n; i += siz)
{
L[++tot] = i, R[tot] = i + siz - 1;
}
for(int i = 1; i <= m; ++i)
{
read(q[i].l), read(q[i].r);
q[i].id = i;
}
sort(q + 1, q + 1 + m, cmp);
int l = 1, r = 0;
for(int i = 1; i <= m; ++i)
{
while(l < q[i].l) sub(a[l++]);
while(l > q[i].l) add(a[--l]);
while(r > q[i].r) sub(a[r--]);
while(r < q[i].r) add(a[++r]);
ok[q[i].id] = Q();
}
for(int i = 1; i <= m; ++i) printf("%d\n", ok[i]);
return 0;
}
2.3数列找不同
2.4小B的询问
3、带修莫队
3.1[国家集训队] 数颜色 / 维护队列
code
#include <bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T& t)
{
int f = 0, c = getchar();
t = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) t = t * 10 + c - 48, c = getchar();
if (f) t = -t;
}
const int N = 1e6 + 10;
int n, m, ans;
int a[N], ok[N], mp[N];
struct qnode
{
int l, r, pre, id, bkl, bkr;
} q[N];
int qnum, cnum;
struct cnode
{
int pos, val;
} c[N];
void change(int now, int i)
{
if(c[now].pos >= q[i].l && c[now].pos <= q[i].r)
{
if(--mp[a[c[now].pos]] == 0) ans--;
if(++mp[c[now].val] == 1) ans++;
}
swap(c[now].val, a[c[now].pos]);
}
void add(int x)
{
if(++mp[x] == 1) ans++;
}
void sub(int x)
{
if(--mp[x] == 0) ans--;
}
inline bool cmp(register qnode a, register qnode b)
{
return a.bkl != b.bkl ? a.bkl < b.bkl : (a.bkr != b.bkr ? a.bkr < b.bkr : a.pre < b.pre);
}
void moqueue()
{
int l = 1, r = 0, now = 0;
for(int i = 1; i <= qnum; ++i)
{
while(l < q[i].l) sub(a[l++]);
while(l > q[i].l) add(a[--l]);
while(r < q[i].r) add(a[++r]);
while(r > q[i].r) sub(a[r--]);
while(now < q[i].pre) now++, change(now, i);
while(now > q[i].pre) change(now, i), now--;
ok[q[i].id] = ans;
}
for(int i = 1; i <= qnum; ++i) cout << ok[i] << "\n";
}
signed main()
{
read(n), read(m);
int siz = pow(n, 2.0 / 3.0);
for(int i = 1; i <= n; ++i)
{
read(a[i]);
}
char op[N];
while(m--)
{
scanf("%s", op);
if(*op == 'Q')
{
read(q[++qnum].l);
read(q[qnum].r);
q[qnum].pre = cnum;
q[qnum].id = qnum;
q[qnum].bkl = (q[qnum].l - 1) / siz + 1;
q[qnum].bkr = (q[qnum].r - 1) / siz + 1;
}
else
{
read(c[++cnum].pos);
read(c[cnum].val);
}
}
sort(q + 1, q + 1 + qnum, cmp);
moqueue();
return 0;
}

浙公网安备 33010602011771号