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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!