洛谷 [DTCPC2024] mex,min,max 题解
Description
给你一个数列 \(\{a_n\}\) 和正整数 \(k\),求有几组 \([l,r]\) 满足 \(\text{mex}(l,r)+\min(l,r)+k\geq\max(l,r)\)。
Solution
来一发不用脑子的做法。
Part I
观察到一个性质:对于一个区间,\(\text{mex}=0\) 与 \(\min=0\) 至少成立一个。证明显然。
记 \(A\) 为 \(\text{mex}+k\geq\max\) 的区间个数,\(B\) 为 \(\min+k\geq\max\) 的区间个数,\(C\) 为 \(\max\leq k\) 的区间个数。
根据性质,简单容斥一下,答案 \(ans=A+B-C\)。
\(B,C\) 好求,因为固定了右端点后合法的左端点在一个区间内,枚举右端点二分左端点即可。这部分用 ST 表处理极值,可以做到 \(\mathcal{O}(n\log n)\)。
考虑怎么求 \(A\)。
Part II
你如果做过 [THUPC 2024 初赛] 套娃 的话,就会知道一个叫『极小 mex 区间』的东西。
一个结论是这样的『极小 mex 区间』只有 \(\mathcal{O}(n)\) 个。所以用那题的做法求出所有『极小 mex 区间』,并对每个『极小 mex 区间』求出包含它的『极大 mex 区间』。这部分可以做到 \(\mathcal{O}(n\log n)\)。
枚举所有极小区间。对于一个极小区间 \([l,r]\),它的 \(\text{mex}\) 为 \(p\),极大区间为 \([L,R]\)。那么对于 \(\forall l'\in[L,l],r'\in[r,R]\),\(\text{mex}(l',r')=p\)。这样,\(\text{mex}+k\) 就固定了。二分出极大的区间 \([l',r']\),使得 \(l'\in[L,l],r'\in[r,R]\) 且 \(p+k\geq \max(l'\,r')\)。\(\forall pl\in[l',l],pr\in[r,r']\),\([pl,pr]\) 是合法区间。
我们发现这样求合法区间不漏但是会重。不过没关系,直接扫描线,对所有 \((l',l)(r',r)\) 组成的矩阵求面积并就行了。这部分复杂度为 \(\mathcal{O}(n\log n)\)。
总复杂度 \(\mathcal{O}(n\log n)\),可以通过。码量其实没有想象中多,只有 4K 不到,而且好调。
实现的时候二分容易出错,所以把二分换成了更简洁的倍增。
Code
// writer: Milkcat
// time: 2024.2.17
#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
#define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define pb emplace_back
#define mems(x, v) memset((x), (v), sizeof(x))
using namespace std;
namespace Milkcat {
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 5e5 + 5;
namespace HJT {
int cnt, s[N << 5], Ls[N << 5], Rs[N << 5];
int modify(int p, int l, int r, int t, int k) {
int rt = ++ cnt; Ls[rt] = Ls[p], Rs[rt] = Rs[p];
if (l == r) return s[rt] = k, rt;
int mid = (l + r) >> 1;
if (t <= mid) Ls[rt] = modify(Ls[p], l, mid, t, k);
if (t > mid) Rs[rt] = modify(Rs[p], mid + 1, r, t, k);
s[rt] = min(s[Ls[rt]], s[Rs[rt]]);
return rt;
}
int query(int p, int l, int r, int k) {
if (l == r) return l;
int mid = (l + r) >> 1;
if (s[Ls[p]] < k) return query(Ls[p], l, mid, k);
return query(Rs[p], mid + 1, r, k);
}
}
namespace SGT {
LL sum[N << 3], ass[N << 3];
void pushup(int p, int l, int r) {
if (ass[p]) sum[p] = r - l + 1;
else sum[p] = sum[p << 1] + sum[p << 1 | 1];
}
void upd(int p, int l, int r, int nl, int nr, int k) {
if (nl <= l && r <= nr) { ass[p] += k, pushup(p, l, r); return; }
int mid = (l + r) >> 1;
if (nl <= mid) upd(p << 1, l, mid, nl, nr, k);
if (nr > mid) upd(p << 1 | 1, mid + 1, r, nl, nr, k);
pushup(p, l, r);
}
}
int n, k, a[N], rt[N], cnt[N], mn[22][N], mx[22][N]; LL ans;
vector<pii> g[N]; vector<int> vec[N];
vector<tuple<int, int, int>> s[N];
int mex(int l, int r) { return HJT::query(rt[r], 0, n, l); }
int main() {
cin >> n >> k;
REP(i, 1, n) {
cin >> a[i], mx[0][i] = mn[0][i] = a[i];
rt[i] = HJT::modify(rt[i - 1], 0, n, a[i], i);
vec[a[i]].pb(i), g[a[i] > 0 ? 0 : 1].pb(pii(i, i));
}
auto Pre = [&](int t, int x) {
auto it = lower_bound(vec[x].begin(), vec[x].end(), t);
return (it == vec[x].begin() ? 0 : *prev(it));
};
auto Nxt = [&](int t, int x) {
auto it = upper_bound(vec[x].begin(), vec[x].end(), t);
return (it == vec[x].end() ? n + 1 : *it);
};
REP(i, 0, n) {
for (pii t : g[i - 1]) {
int l = Pre(t.fi, i - 1), r = Nxt(t.se, i - 1);
if (l >= 1) g[mex(l, t.se)].pb(pii(l, t.se));
if (r <= n) g[mex(t.fi, r)].pb(pii(t.fi, r));
}
vector<pii> tmp; int las = 1e9;
sort(g[i].begin(), g[i].end(), [&](pii x, pii y) { return x.fi == y.fi ? x.se < y.se : x.fi > y.fi; });
for (auto t : g[i]) if (las > t.se) tmp.pb(t), las = t.se;
g[i].swap(tmp);
}
REP(j, 1, __lg(n)) REP(i, 1, n - (1 << j) + 1) {
mx[j][i] = max(mx[j - 1][i], mx[j - 1][i + (1 << (j - 1))]);
mn[j][i] = min(mn[j - 1][i], mn[j - 1][i + (1 << (j - 1))]);
}
auto ask = [&](int l, int r) -> pii {
int d = __lg(r - l + 1);
return {max(mx[d][l], mx[d][r - (1 << d) + 1]), min(mn[d][l], mn[d][r - (1 << d) + 1])};
};
REP(i, 0, n) for (auto [l, r] : g[i]) {
if (i + k < ask(l, r).fi) continue;
int L = l + 1, R = r - 1, Lm = Pre(l, i) + 1, Rm = Nxt(r, i) - 1;
DEP(j, __lg(n), 0) {
int t = L - (1 << j);
if (t >= Lm && i + k >= ask(t, l).fi) L = t;
}
DEP(j, __lg(n), 0) {
int t = R + (1 << j);
if (t <= Rm && i + k >= ask(r, t).fi) R = t;
}
s[L].pb(r, R, 1), s[l + 1].pb(r, R, -1);
}
REP(i, 1, n) {
for (auto [l, r, v] : s[i]) SGT::upd(1, 1, n, l, r, v);
ans += SGT::sum[1];
}
REP(R, 1, n) {
int L = R + 1;
DEP(i, __lg(n), 0) {
int t = L - (1 << i);
auto [mx, mn] = ask(t, R);
if (t >= 1 && mx - mn <= k) L = t;
}
ans += R - L + 1;
}
REP(R, 1, n) {
int L = R + 1;
DEP(i, __lg(n), 0) {
int t = L - (1 << i);
if (t >= 1 && ask(t, R).fi <= k) L = t;
}
ans -= R - L + 1;
}
cout << ans << '\n';
return 0;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
while (T --) Milkcat::main();
return 0;
}