区间 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){
        
	}
}

P13780