間隔について\(MEX \)いくつかの実践
効果の対象に
シークで\(SGの\)を介して機能を言及\(MEX \)機能;
({a_iを\})\ MEX(\)\表す\(A \)最小の自然数で、表示されない\(a_iを\ N \で\) 。
長さに\(N- \)シーケンス\(\)、\ (M \)クエリ、各クエリ\(MEX(\ {a_iを\ })、iが\ [L、R]で\)
1、のMo +チームフェンウィックツリー
フェンウィックツリーが出現重み数のそれぞれを維持するために、
複雑:\(O(Mの\ SQRT N-logN個)\)
2、Moの+チームのブロック
重量サブブロック、各ブロックは、数が少ない登場維持し、
複雑:$ O((N + M )\ SQRT N)
コード次のように
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
const int N = 2e5 + 5;
int blo, bl[N];
struct query {
int l, r, id;
} q[N];
int n, m;
int a[N], res[N];
inline bool cmp (const query &i, const query &j) {
if (bl[i.l] != bl[j.l])
return bl[i.l] < bl[j.l];
if (bl[i.l] & 1)
return i.r < j.r;
return i.r > j.r;
}
struct block_split {
int a[N], b[1000];
inline void modify(int p, int k) {
if (!a[p])
++b[bl[p]];
a[p] += k;
if (!a[p])
--b[bl[p]];
}
int query() {
int i;
for (i = 1; i < bl[n]; ++i)
if (b[i] < blo)
break;
for (int j = (i - 1) * blo; j <= std::min(n, i * blo - 1); ++j)
if (!a[j])
return j;
return n;
}
} B;
inline void add(const int p) {
B.modify(a[p], 1);
}
inline void rem(const int p) {
B.modify(a[p], -1);
}
int main() {
n = in(), m = in();
for (int i = 1; i <= n; ++i)
a[i] = in(), chk_min(a[i], n);
for (int i = 1; i <= m; ++i)
q[i] = (query){in(), in(), i};
blo = (int)sqrt(n + 1);
for (int i = 0; i <= n; ++i)
bl[i] = i / blo + 1;
std::sort(q + 1, q + 1 + m, cmp);
for (int i = 1, l = 1, r = 0; i <= m; ++i) {
for (; l > q[i].l; add(--l));
for (; r < q[i].r; add(++r));
for (; l < q[i].l; rem(l++));
for (; r > q[i].r; rem(r--));
res[q[i].id] = B.query();
}
for (int i = 1; i <= m; ++i)
printf("%d\n", res[i]);
return 0;
}
3、木の会長
オフラインに上記のアプローチ、木の会長は、オンラインのお問い合わせ、およびより優れたの複雑さに対処することができます。
木のメンテナンスの会長最初の各番号\(私は\)歴史のバージョン前の位置、最後に出現しました。
クエリの集合のための\(L、Rの\) 、最初の\(R \)番目の版の歴史の中で最後の時間を見つける\(1- \)プレ歴史的バージョンの最小数。
コードは以下の通りであります:
#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
int x = 0; char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x;
}
const int N = 2e5 + 5;
struct persistable_tree {
int min[20 * N], rt[20 * N], c[20 * N][2];
int tot;
void modify(int pos, int k, int tl, int tr, int pre, int &p) {
p = ++tot;
if (tl == tr)
return (void)(min[p] = k);
c[p][0] = c[pre][0], c[p][1] = c[pre][1];
int mid = (tl + tr) >> 1;
if (mid >= pos)
modify(pos, k, tl, mid, c[pre][0], c[p][0]);
else
modify(pos, k, mid + 1, tr, c[pre][1], c[p][1]);
min[p] = std::min(min[c[p][0]], min[c[p][1]]);
}
int query(int k, int tl, int tr, int p) {
if (tl == tr)
return tl;
int mid = (tl + tr) >> 1;
if (min[c[p][0]] < k)
return query(k, tl, mid, c[p][0]);
else
return query(k, mid + 1, tr, c[p][1]);
}
} T;
int main() {
int n = in(), m = in();
for (int i = 1, x; i <= n; ++i) {
x = in();
T.modify(x, i, 0, n, T.rt[i - 1], T.rt[i]);
}
int l, r;
while (m--) {
l = in(), r = in();
printf("%d\n", T.query(l, 0, n, T.rt[r]));
}
return 0;
}