题解:P9970 [THUPC 2024 初赛] 套娃
lovely_nst · · 题解
P9970 套娃
前置知识
-
主席树(动态开点权值线段树)
-
set 维护
\text{mex}
在线区间 \text{mex}
考虑确定右端点后
极小 \text{mex} 区间
设
结论是极小 我不会证。
那么如何求呢?对于
每次要进行去重,即只保留小区间,包含小区间的大区间删除。
答案
对于每个极小
之后用扫描线 set 动态维护
注意在
AC Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100000 , M = 20 * N + 5 , inf = 1e9;
int cc , siz , st[N + 5];
struct STree
{
int idx = 0;
int lc[M] = {0} , rc[M] = {0} , d[M] = {0};
void push_up (int p) { d[p] = min (d[lc[p]] , d[rc[p]]); }
void bld (int &p , int s = 1 , int t = siz)
{
p = ++ idx;
if (s == t) return ;
int mid = s + t >> 1;
bld (lc[p] , s , mid);
bld (rc[p] , mid + 1 , t);
}
void add (int &p , int q , int ps , int c , int s = 1 , int t = siz)
{
p = ++ idx;
if (s == t)
{
d[p] = c;
return;
}
int m = s + t >> 1;
if (ps <= m) rc[p] = rc[q] , add (lc[p] , lc[q] , ps , c , s , m);
else lc[p] = lc[q] , add (rc[p] , rc[q] , ps , c , m + 1 , t);
push_up (p);
}
int qry (int p , int w , int s = 1 , int t = siz)
{
if (s == t)
return s - 1;
int m = s + t >> 1;
if (d[lc[p]] >= w) return qry (rc[p] , w , m + 1 , t);
else return qry (lc[p] , w , s , m);
}
} T;
int n , x;
vector <pair <int , int> > mex[N + 5] , ln[N + 5];
vector <int> s[N + 5] , g[N + 5];
bool cmp (pair <int , int> x , pair <int , int> y)
{
if (x.first != y.first) return x.first > y.first;
return x.second < y.second;
}
bool cmp2 (pair <int , int> x , pair <int , int> y)
{
if (x.first != y.first) return x.first < y.first;
return x.second > y.second;
}
signed main ()
{
ios::sync_with_stdio (0) , cin.tie (0) , cout.tie (0);
T.d[0] = inf;
cin >> n;
siz = n + 3;
T.bld (st[0]);
for (int i = 0;i <= n + 1;i ++) s[i].push_back (0);
for (int i = 1;i <= n;i ++)
{
cin >> x;
T.add (st[i] , st[i - 1] , x + 1 , i);
if (!x) mex[1].push_back ({i , i});
else mex[0].push_back ({i , i});
s[x].push_back (i);
}
for (int i = 0;i <= n + 1;i ++) s[i].push_back (n + 1);
for (int i = 0;i <= n;i ++)
{
sort (mex[i].begin () , mex[i].end () , cmp);
vector <pair <int , int> > now;
int mn = 1e9;
for (auto w : mex[i])
if (mn > w.second)
now.push_back (w) , mn = w.second;
reverse (now.begin () , now.end ());
mex[i] = now;
for (auto w : mex[i])
{
int l = w.first , r = w.second;
int L = *(lower_bound (s[i].begin () , s[i].end () , l) - 1) , R = *upper_bound (s[i].begin () , s[i].end () , r);
if (L)
{
int _mex = T.qry (st[r] , L);
mex[_mex].push_back ({L , r});
}
if (R <= n)
{
int _mex = T.qry (st[R] , l);
mex[_mex].push_back ({l , R});
}
}
}
multiset <int> S;
for (int i = 0;i <= n + 1;i ++)
{
S.insert (i);
for (auto w : mex[i])
{
int l = w.first , r = w.second;
int L = *(lower_bound (s[i].begin () , s[i].end () , l) - 1) , R = *upper_bound (s[i].begin () , s[i].end () , r);
ln[i].push_back ({r - l + 1 , R - L - 1});
}
}
S.insert (n + 2);
for (int i = 0;i <= n;i ++)
{
int mx = 0;
vector <pair <int , int> > now;
sort (ln[i].begin () , ln[i].end () , cmp2);
for (auto w : ln[i])
if (mx < w.second)
mx = w.second , now.push_back (w);
int len = now.size ();
for (int i = 1;i < len;i ++)
now[i].first = max (now[i].first , now[i - 1].second + 1);
for (auto w : now)
g[w.first].push_back (i + 1) , g[w.second + 1].push_back (-i - 1);
}
for (int i = 1;i <= n;i ++)
{
for (int w : g[i])
{
if (w < 0) S.insert (-w - 1);
else S.erase (w - 1);
}
cout << *S.begin () << ' ';
}
return 0;
}