CF1436E Complicated Computations

题面传送门
首先考虑一个结论:将一个区间中的数去重后这个区间 m e x mex mex没有影响。
所以我们只要求出那些 m e x mex mex中有几个数。
一个区间 m e x = k mex=k mex=k的条件是区间没有 k k k且区间有 1 1 1 k − 1 k-1 k1
考虑对于同样的数分段。
那么对于每个段这样查询即可。
即满足两个条件: [ l ≤ i ≤ r ] [l\leq i \leq r] [lir]和所有不同的 1 ∼ k − 1 1\sim k-1 1k1种类等于 k − 1 k-1 k1
如果直接像 H H 的 项 链 HH的项链 HH那样那就要二维树状数组维护要两个 l o g log log
转化一下,则就是判断 1 ∼ k − 1 1 \sim k-1 1k1中最小的出现的位置是否小于 l l l
那么就可以复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
代码实现:

#include<cstdio>
#include<vector>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,ans[100039],a[100039],pus,maxn;
int last[100039],f[400039],g[100039];
inline void get(int x,int z,int l,int r,int now){
	if(l==r){f[now]=z;return;}
	int m=(l+r)>>1;
	if(x<=m) get(x,z,l,m,now<<1);
	else get(x,z,m+1,r,now<<1|1);
	f[now]=min(f[now<<1],f[now<<1|1]);
}
inline int find(int x,int y,int l,int r,int now){
	if(x<=l&&r<=y) return f[now];
	int m=(l+r)>>1,fs1=1e9,fs2=1e9;
	if(x<=m) fs1=find(x,y,l,m,now<<1);
	if(y>m)fs2=find(x,y,m+1,r,now<<1|1);
	return min(fs1,fs2);
}
int main(){
//	freopen("1.in","r",stdin);
	register int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%d",&a[i]),maxn=max(maxn,a[i]),ans[1]|=(a[i]!=1?1:0),ans[2]|=(a[i]==1?1:0);
	for(i=1;i<=n;i++){
		g[i]=last[a[i]];
		last[a[i]]=i;
	}
	for(i=1;i<=n;i++){
		get(a[i],i,1,n+1,1);
		if(a[i]!=1){
			pus=find(1,a[i]-1,1,n+1,1);
			//printf("%d %d\n",a[i],pus);
			if(pus>g[i]) ans[a[i]]=1; 
		}
	}
	for(i=2;i<=maxn+1;i++){
	//	printf("%d %d\n",i,find(1,i-1,1,n+1,1));
		if(find(1,i-1,1,n+1,1)>last[i]) ans[i]=1;
	}
	for(i=1;i<=n+2;i++) if(!ans[i]){printf("%d\n",i);return 0;}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值