codeforces 1436E - Complicated Computations (思维 + 线段树)

题目链接:https://codeforces.com/problemset/problem/1436/E

对于一个答案\(x\),考虑\(x\)可以是子区间\(mex\)值的条件:
首先\(x\)不能在子区间中出现过,所以可以将序列划分成以\(x\)为分割点的子区间
其次是在这样的子区间中,\([1,x-1]\)全部都出现过

\(lst[i]\) 表示 \(i\) 最后一次出现的位置,那么每扫到一个新元素\(a[i]\),就判断一下\([i,a[i]-1]\)最后一次出现的位置
是不是都比\(lst[i]\)大,也即是否都出现在了这段子区间中
可以使用线段树实现,线段树维护的是元素最后一次出现的位置

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 100010;

int n,cnt,N;
int a[maxn],lst[maxn];
bool mex[maxn];

struct SEG{
	int mi,add;
}t[maxn<<2];

void pushup(int i){ t[i].mi = min(t[i<<1].mi,t[i<<1|1].mi); }

void mdf(int i,int l,int r,int p,int k){
	if(l == r){
		t[i].mi = k;
		return;
	}
	int mid = (l+r)/2;
	if(p<=mid) mdf(i<<1,l,mid,p,k);
	else mdf(i<<1|1,mid+1,r,p,k);
	pushup(i);
}

int qry(int i,int l,int r,int x,int y){
	if(x <= l && r <= y){
		return t[i].mi;
	}
	int mid = (l+r)/2;
	int mi = 1000000007;
	if(x <= mid) mi = min(mi,qry(i<<1,l,mid,x,y));
	if(y > mid) mi = min(mi,qry(i<<1|1,mid+1,r,x,y));
	return mi;
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
	n = read();
		
	for(int i=1;i<=n;++i){
		a[i] = read();
		if(a[i] != 1) mex[1] = 1; // 对 1 特判
		mdf(1,1,n,a[i],i);
		
		if(a[i] > 1 && qry(1,1,n,1,a[i]-1) > lst[a[i]]) mex[a[i]] = 1;
		lst[a[i]] = i;
	}
	
	for(int i=2;i<=n+1;++i){ if(qry(1,1,n,1,i-1) > lst[i]) mex[i] = 1; } // 处理最后一段区间
	
	int ans = 1;
	for(;mex[ans] && ans <= n+1;) ++ans;
	
	printf("%d\n",ans);
	
	return 0;
}
posted @ 2020-10-26 01:02  Tartarus_li  阅读(198)  评论(0编辑  收藏  举报