CF1436 E. Complicated Computations MEX性质分析+权值线段树维护区间种类

思维量比较大的一道题,如果之前做过类似的就很简单,但没做过的话真的有点难想。。

首先一个比较容易想到的点:

从1枚举到n+1,用某种方法计算最终的MEX序列是否出现i。

 对于一个子数组[L,R],若其MEX等于x,则其必须满足:区间内不包含x,且区间内包含所有1 -  x-1的数。

关键点在于这里如何进行维护。

我们可以这样做:

对于区间不好含x这个限制我们可以每次取区间:(lst[a[i]],i),这样区间一定不包含a[i],而包含1 - x-1的数可以考虑用权值线段树维护:

从左往右枚举,线段树维护当前状态下值为i的数,最后一次出现的位置。

这样我们求区间1 - x-1 的min,如果它大于lst[a[i]],说明区间(lst[a[i]],i)包含1 - x-1的所有数。

枚举更新即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int a[M],lst[M],vs[M];
int n;
int tr[M<<2];
void up(int o,int l,int r,int x,int d){
	if(l==r){
		tr[o]=d;
		return ;
	}
	if(x<=m)up(ls,l,m,x,d);
	else up(rs,m+1,r,x,d);
	tr[o]=min(tr[ls],tr[rs]);
} 
int qu(int o,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		return tr[o];
	}
	int ans=1e9;
	if(x<=m)ans=min(ans,qu(ls,l,m,x,y));
	if(y>m)ans=min(ans,qu(rs,m+1,r,x,y));
	return ans;
}
int main(){
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n;
  	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	//up(1,1,n,i,n+1);
	//cout<<qu(1,1,n,1,1)<<" --  "<<endl;
	for(int i=1;i<=n;i++){
		if(a[i]==1){
			vs[2]=1;
			up(1,1,n,a[i],i);//单点赋值 
			continue;
		}
		vs[1]=1;
		int L=lst[a[i]]+1,R=i-1;
	//	cout<<i<<" "<<L<<" -> "<<a[i]<<" "<<qu(1,1,n,1,a[i]-1)<<endl;
		
		if(qu(1,1,n,1,a[i]-1)>=L)
			vs[a[i]]=1;
		up(1,1,n,a[i],i);//单点赋值 
	//	cout<<"--->  "<<qu(1,1,n,a[i],a[i])<<endl;
		lst[a[i]]=i;
	} 
	for(int i=2;i<=n+1;i++){
		int L=lst[i]+1;
	//	cout<<" =  "<<i<<" "<<L<<" -> "<<i<<" "<<qu(1,1,n,1,i-1)<<endl;
		if(qu(1,1,n,1,i-1)>=L)
			vs[i]=1;
	}
	for(int i=1;i<=n+7;i++){
		if(!vs[i]){
			cout<<i<<endl;
			return 0;
		}
	}
	return 0;
}
/*
9
5 4 3 2 1 2 3 4 5
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值