Codeforces Round #767 (Div. 2) C. Meximum Array(主席树/整活解法)
Mihai has just learned about the MEX concept and since he liked it so much, he decided to use it right away.
Given an array 𝑎a of 𝑛n non-negative integers, Mihai wants to create a new array 𝑏b that is formed in the following way:
While 𝑎a is not empty:
- Choose an integer 𝑘k (1≤𝑘≤|𝑎|1≤k≤|a|).
- Append the MEX of the first 𝑘k numbers of the array 𝑎a to the end of array 𝑏b and erase them from the array 𝑎a, shifting the positions of the remaining numbers in 𝑎a.
But, since Mihai loves big arrays as much as the MEX concept, he wants the new array 𝑏b to be the lexicographically maximum. So, Mihai asks you to tell him what the maximum array 𝑏b that can be created by constructing the array optimally is.
An array 𝑥x is lexicographically greater than an array 𝑦y if in the first position where 𝑥x and 𝑦y differ 𝑥𝑖>𝑦𝑖xi>yi or if |𝑥|>|𝑦||x|>|y| and 𝑦y is a prefix of 𝑥x (where |𝑥||x| denotes the size of the array 𝑥x).
The MEX of a set of non-negative integers is the minimal non-negative integer such that it is not in the set. For example, MEX({1,2,31,2,3}) =0=0 and MEX({0,1,2,4,50,1,2,4,5}) =3=3.
倒着建主席树,然后正序遍历数组,不断计算目前为止的mex,如果在某个位置mex发生变化,说明这个位置可能会分段,此时主席树check这个位置以后是否存在和当前mex相等的数,如果不存在则此处分段一定最优,同时mex置0,继续处理后面的位置。
#include <iostream>
#include <vector>
#define ll long long
using namespace std;
int n, a[200005], b[200005];
int cnt[200005];
#define R register int
const int N=4000009,M=10000009;
int P,rt[N],lc[M],rc[M],val[M];
char I[M<<1],O[M],*fi=I,*fo=O;
bool nega;
inline void in(R&z)
{
while(*fi<'-')++fi;
if(*fi=='-')nega=1,++fi;
z=*fi++&15;
while(*fi>'-')z*=10,z+=*fi++&15;
if(nega)nega=0,z=-z;
}
void oi(R z)
{
if(z>9)oi(z/10);
*fo++=z%10|'0';
}
inline void out(R z)
{
z>0?oi(z):(*fo++='-',oi(-z));*fo++='\n';
}//上面快读快写
void build(R&t,R l,R r)//初始化建树,线段树基本操作
{
R m;
t=++P;
if(l!=r)
{
m=(l+r)>>1;
build(lc[t],l,m);
build(rc[t],m+1,r);
}
else val[P] = 0;
}
inline void insert(R*t,R u,R l,R r,R k)//更新,插入一个新路径
{
R m;
while(l!=r)
{
*t=++P;
m=(l+r)>>1;
if(k<=m)r=m,rc[*t]=rc[u],t=&lc[*t],u=lc[u];
else l=m+1,lc[*t]=lc[u],t=&rc[*t],u=rc[u];
}
val[*t=++P]++;
}
inline int ask(R t,R l,R r,R k)//询问
{
R m;
while(l!=r)
{
m=(l+r)>>1;
if(k<=m)r=m,t=lc[t];
else l=m+1,t=rc[t];
}
return val[t];
}
int main() {
int t;
cin >> t;
while(t--) {
cin >> n;
cnt[0] = 0;
for(int i = 1; i <= n; i++) {
cin >> a[i];
cnt[i] = 0;
}
int mex = 0;
build(rt[0],0,n);
for(int i = 1; i <= n; i++) {
insert(&rt[i],rt[i - 1],0,n,a[n - i + 1]);
}
for(int i = 1; i <= n; i++) {
cnt[i] = 0;
}
vector<int> ans;
mex = 0;
b[0] = -1;
int lst = 1;
for(int i = 1; i <= n; i++) {
cnt[a[i]]++;
while(cnt[mex]) mex++;
b[i] = mex;
int tmp = ask(rt[n - i], 0, n, mex);
if((b[i] != b[i - 1] || lst == i) && tmp == 0) {//注意不要忘了区间新开始的情况
ans.push_back(mex);
for(int j = lst; j <= i; j++) {
cnt[a[j]]--;
}
lst = i + 1;
mex = 0;
}
}
if(ans.size() == 0) {
cout << n << endl;
for(int i = 1; i <= n; i++) {
cout << 0 << " ";
}
cout << endl;
} else {
if(lst <= n) {
for(int i = lst; i <= n; i++) ans.push_back(0);
}
cout << ans.size() << endl;
for(auto x : ans) {
cout << x << " ";
}
cout << endl;
}
}
return 0;
}
// 1
// 5
// 0 1 0 0 0