区间 mex 在平面上的矩形个数 。
从 到 ,set 维护 的连续段,单调递减。删去 即 对 取 min,即区间推平。
极小 mex 区间 个
只考虑 的极小 mex 区间。设 是,则 。若存在 且 也是,, 中有 ,可以删去 ,矛盾。
从小到大维护出 的极小 mex 区间。对于一个 ,找到 ,拓展为 和 作为对应的 mex 的候选区间。对于 的候选区间,删掉不优的即可。
主席树维护在线询问。
在求出最小 mex 区间后,可以再类似区间推平得到极大 mex 区间。
这样等价于求出矩形 后的 和 ,点数更小些。
code
int n,a[maxn];
struct node{
int l,r,v,t;
bool operator<(const node&tmp)const{return r<tmp.l;}
};
set<node> s;
bool vis[maxn];
int pos[maxn],pre[maxn];
vector<tuple<int,int,int,int,int>> b;
void work(){
n=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=n,mex=1;i;i--){
vis[a[i]]=1;while(vis[mex])mex++;
s.insert({i,i,mex,n});
}
for(int i=1;i<=n;i++)pre[i]=pos[a[i]],pos[a[i]]=i;
for(int i=n;i;i--){
{
auto it=s.find({i,i,0,0});
auto[l,r,v,t]=*it;s.erase(it);
if(l<i)s.insert({l,i-1,v,t});
b.pb({v,i,i,i,t});
}
if(pre[i]+1==i)continue;
{
auto it=s.find({pre[i]+1,pre[i]+1,0,0});
auto[l,r,v,t]=*it;
if(l<=pre[i]){
s.erase(it);
s.insert({l,pre[i],v,t});
s.insert({pre[i]+1,r,v,t});
}
}
auto it=s.find({pre[i]+1,pre[i]+1,0,0});
int p=pre[i];
while(it!=s.end()&&(*it).v>a[i]){
auto[l,r,v,t]=(*it);it=s.erase(it);
b.pb({v,l,r,i,t});p=r;
}
if(pre[i]+1<=p)s.insert({pre[i]+1,p,a[i],i-1});
}
for(auto[v,l1,r1,l2,r2]:b){
}
}