题意,有一个长度为 $n$ 的序列,每个点权值为在范围 $[1, m]$ 内,并且保证每个值都出现过
对每个 $i(1 \leqslant i \leqslant m)$ 询问包含权值 $[1, i]$ 的最小区间长度
具体来说,$f(i, x)$ 表示以 $[i \cdots)$ 作为左端点,并且包含 $[1\cdots x]$ 所有值(即编号为 $[1\cdots x]$ 的网络)
此时最近的右端点,记为 $f(i, x)$
另外用 $\textbf{A}_x[\cdots]$ 表示 $x$ 网络出现的位置
-
很容易想到一种 $O(n^2)$ 的算法,状态转移方程是 $f(i, x) = \max (f(i, x-1), \min (\textbf{A}_x[\cdots]))$
用 $\text{last}$ 记录 $\textbf{A}_x[\cdots]$ 中离 $i$ 最近的位置
那么 $f(i, x) = \max (f(i, x-1), \text{last})$ -
考虑优化,对于 $\textbf{for} \ \forall x \in [1\cdots m]$
尝试维护 $\forall i \in [1\cdots n]$ 中的 $f_x(i)$,其中保证 $[i\cdots f_x(i)]$ 中 $[1\cdots x]$ 的每个数都出现
这样可以用 $\min (f_x(i) - i + 1)$ 来更新全局的 $res$ -
$\textbf{A}[x] = \{p_1, \cdots p_{j-1}, p_j \cdots p_k \}$,当 $p_{j-1} \to p_j$
转移的时候,考虑区间 $[p_{j-1}+1\cdots p_j]$
对于 $\forall \ i \leqslant p_{j-1}$,$p_j$ 处出现的 $x$ 不影响 $f_x(i)$ 的值
而 $\forall \ i \in [p_{j-1} + 1 \cdots p_j]$,要更新所有的 $f_x(i) \leftarrow \max (f_x(i), p_j)$
但注意到对于 $\forall i \in [p_{j-1}+1 \cdots p_j]$,$p_j$ 只会影响到 $f_x(i) < p_j$ 的 $i$
也就是说,我们只需要更新 $[p_{j-1}+1, p_j]$ 的某一段子区间即可,不妨设为 $[p_{j-1}+1, pos]$
注意单调性,对于 $i_1 < i_2$,有 $f_x(i_1) \leqslant f_x(i_2)$
$i \leqslant pos$, $f_x(i) \leqslant f_x(pos)$,只需要修改 $[p_{j-1}+1, pos]$ 即可 -
要求出 $pos$,可以考虑在区间 $i \in [1\cdots n]$ 上建线段树,节点 $u$ 表示区间 $[t_u.l, t_u.r]$
$t_u.f$ 维护 $\forall i \in [t_u.l, t_u.r]$ 的 $f_x(i)$ 信息
在线段树上二分查找,找到满足 $t_u.f < p_j$ 的最大叶节点,$pos \leftarrow t_u.l$ -
接下来在线段树找到区间 $u = [p_{j-1}+1, pos]$,并且执行区间赋值 $t_u.f \leftarrow p_j$
此时 $i \in [t_u.l, t_u.r] = [p_{j-1}+1, pos]$ 所有的 $f_x(i)$ 都相等
最短的包含 $[1\cdots x]$ 所有数的区间的长度 $\textbf{len}(x) = t_u.f - t_u.r + 1$
自底向上 $\textbf{pull}$ 取 $\min$,最后 $t_1.len$ 就是 $\textbf{len}(x)$ 对应的答案
特别地,$\textbf{A}[x] = \{p_1, \cdots, p_k \}$,对于 $i \in [p_{k}+1, \cdots n]$ 这一段,
不存在满足 $[1\cdots x]$ 所有数都出现的区间段,这里只要将这个区间段的 $t_u.f \leftarrow +\infty$
这样更新 $\min$ 的时候就用不到这一段了 -
综上所述,线段树维护 $f$,表示 $f_x(i)$,另外需维护 $\min$,表示 $[t_u.l, t_u.r]$ 对应的最小 $\text{len}(x)$
初始化 $\min$ 为 $+\infty$,$f$ 为 $0$,每次处理完 $\textbf{A}={p_1\cdots p_k}$ 时
将 $[p_k+1, n]$ 的 $f$ 置为 $+\infty$
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <bitset>
#include <assert.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
#define Cmp(a, b) memcmp(a, b, sizeof(b))
#define Cpy(a, b) memcpy(a, b, sizeof(b))
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define _forS(i, l, r) for(set<int>::iterator i = (l); i != (r); i++)
#define _rep(i, l, r) for(int i = (l); i <= (r); i++)
#define _for(i, l, r) for(int i = (l); i < (r); i++)
#define _forDown(i, l, r) for(int i = (l); i >= r; i--)
#define debug_(ch, i) printf(#ch"[%d]: %d\n", i, ch[i])
#define debug_m(mp, p) printf(#mp"[%d]: %d\n", p->first, p->second)
#define debugS(str) cout << "dbg: " << str << endl;
#define debugArr(arr, x, y) _for(i, 0, x) { _for(j, 0, y) printf("%c", arr[i][j]); printf("\n"); }
#define _forPlus(i, l, d, r) for(int i = (l); i + d < (r); i++)
#define lowbit(i) (i & (-i))
#define MPR(a, b) make_pair(a, b)
pair<int, int> crack(int n) {
int st = sqrt(n);
int fac = n / st;
while (n % st) {
st += 1;
fac = n / st;
}
return make_pair(st, fac);
}
inline ll qpow(ll a, int n) {
ll ans = 1;
for(; n; n >>= 1) {
if(n & 1) ans *= 1ll * a;
a *= a;
}
return ans;
}
template <class T>
inline bool chmax(T& a, T b) {
if(a < b) {
a = b;
return true;
}
return false;
}
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll ksc(ll a, ll b, ll mod) {
ll ans = 0;
for(; b; b >>= 1) {
if (b & 1) ans = (ans + a) % mod;
a = (a * 2) % mod;
}
return ans;
}
ll ksm(ll a, ll b, ll mod) {
ll ans = 1 % mod;
a %= mod;
for(; b; b >>= 1) {
if (b & 1) ans = ksc(ans, a, mod);
a = ksc(a, a, mod);
}
return ans;
}
template <class T>
inline bool chmin(T& a, T b) {
if(a > b) {
a = b;
return true;
}
return false;
}
template<class T>
bool lexSmaller(vector<T> a, vector<T> b) {
int n = a.size(), m = b.size();
int i;
for(i = 0; i < n && i < m; i++) {
if (a[i] < b[i]) return true;
else if (b[i] < a[i]) return false;
}
return (i == n && i < m);
}
// ============================================================== //
const int maxn = 2e5 + 10, inf = 0x3f3f3f3f;
int n, m;
vector<int> G[maxn];
class SegTree {
public:
struct node {
int l, r;
int tag, len, f;
};
int tot = 0;
vector<node> t;
SegTree() = default;
SegTree(int _tot) : tot(_tot) {
assert(tot > 0);
t.resize(tot << 2);
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if (l >= r) {
t[p].f = 0, t[p].len = inf;
return;
}
int mid = (l + r) >> 1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void push(int p) {
if (!t[p].tag) return;
int fv = t[p].tag; t[p].tag = 0;
t[p<<1].tag = fv;
t[p<<1].f = fv;
t[p<<1].len = fv - t[p<<1].r + 1;
t[p<<1|1].tag = fv;
t[p<<1|1].f = fv;
t[p<<1|1].len = fv - t[p<<1|1].r + 1;
}
void pull(int p) {
t[p].len = min(t[p<<1].len, t[p<<1|1].len);
t[p].f = min(t[p<<1].f, t[p<<1|1].f);
}
void change(int p, const int l, const int r, int fv) {
if (l <= t[p].l && t[p].r <= r) {
t[p].tag = fv;
// change
t[p].f = fv;
t[p].len = fv - t[p].r + 1;
return;
}
push(p);
int mid = (t[p].l + t[p].r) >> 1;
if (l <= mid) change(p<<1, l, r, fv);
if (r > mid) change(p<<1|1, l, r, fv);
pull(p);
return;
}
int find(int p, const int l, const int r, int fv) {
if (t[p].l == t[p].r) return t[p].l;
push(p);
int mid = (t[p].l + t[p].r) >> 1;
int res = -1;
if (r > mid && t[p<<1|1].f < fv) res = find(p<<1|1, l, r, fv);
if (res != -1) return res;
if (l <= mid && t[p<<1].f < fv) res = find(p<<1, l, r, fv);
return res;
}
} seg(maxn);
void solve() {
for (int x = 1; x <= m; x++) {
for (int j = 1; j < G[x].size(); j++) {
int l = G[x][j-1] + 1, r = G[x][j];
// find p in [l, r], change [l, p]
int pos = -1;
pos = seg.find(1, l, r, r);
if (pos == -1) continue;
seg.change(1, l, pos, r);
}
seg.change(1, G[x].back()+1, n, inf);
int res = seg.t[1].len;
printf("%d ", res);
}
}
int main() {
//freopen("input.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (int i = 0; i <= m; i++) G[i].push_back(0);
for (int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
G[x].push_back(i);
}
// build
seg.build(1, 1, n);
// solve
solve();
}