CF 1436 E 線段樹+思維

李ac發表於2020-10-29
啊啊啊啊啊 ~~ 我好菜

這道題題意大概是:
求這個序列 任意連續子序列的mex 的mex。
怎麼求呢?
還好,, 有一點點想法。
從小到大列舉答案是誰,判斷它成不成立,
如何判斷呢?
假設列舉的是 x ,如果隨便一個區間中沒有 x ,並且包含 1 ~ x - 1
那麼這個值肯定可以當答案。
然後 問題就是 怎麼判斷 隨便一個區間中沒有 x ,並且包含 1 ~ x - 1 是否成立。
剛開始想的 把x 不在的區間放到vector中,然後 遍歷一下,在主席樹上找這個區間中包不包含1~x - 1.然後突然發現主席樹好像不能這樣找,
於是查題解
差不多就是這樣的思路。
最後判斷那個條件就相當於 從前往後把這個值出現最晚的位置加到線段樹中。查詢1~i - 1 出現的最前面的位置 是否在上一個a[i] 後面。
可能有點繞。。 但是看程式碼就一目瞭然。。

程式碼:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <string>
#include <queue>
#include <cstring>
#include <stack>
#include <map>
#include <bitset>
#include <math.h>
#include <set>
#include <unordered_set>
#include <climits>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef unordered_set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b > 0){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}};
int lb(int x){return  x & -x;}
// friend bool operator < (Node a,Node b)   閲嶈澆
// 8388607
const int inf = INT_MAX;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
const int maxn = 2e5 + 5;
const int M = 8388607;
struct Node
{
	int l,r,num;
}node[maxn << 2];
void build(int l,int r,int no)
{
	node[no].l = l;
	node[no].r = r;
	node[no].num = 0;
	if(l == r)
		return;
	int mid = l + r >> 1;
	build(l,mid,no<<1);
	build(mid + 1,r,no<<1|1);
}
void update(int pos,int no,int num)
{
	if(node[no].l == node[no].r)
	{
		node[no].num = num;
		return;
	}
	int mid = node[no].l + node[no].r >> 1;
	if(pos <= mid)
		update(pos,no<<1,num);
	else
		update(pos,no<<1|1,num);
	node[no].num = min(node[no<<1].num,node[no<<1|1].num);
}
int query(int l,int r,int no)
{
	if(node[no].l > r || node[no].r < l)
		return inf;
	if(node[no].l >= l && node[no].r <= r)
	{
		return node[no].num;
	}
	return min(query(l,r,no<<1),query(l,r,no<<1|1));
}
int a[maxn];
int per[maxn];
int ans[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	int f = 1;
	for (int i = 1;i <= n; i ++ )
	{
		scanf("%d",&a[i]);
		if(a[i] > 1)
			f =0;
	}
	if(f)
	{
		printf("1\n");
		return 0;
	}
	build(1,n,1);
	
	for (int i = 1; i <= n; i ++ )
	{
		update(a[i],1,i);
		int x = query(1,a[i] - 1,1); // 查詢之前的數出現的最前面的 
		if(x > per[a[i]])
		{
			ans[a[i]] = 1;
		}
		per[a[i]] = i;
	}
	for (int i = 1;i <= n; i ++ )
	{
		int x = query(1,i - 1,1);
		if(x > per[i])
			ans[i] = 1;
//		printf("%d %d %d\n",x,per[])
	}
//	printf("%d %d\n",query(1,n - 1,1),per[n]);
	for (int i = 1; i <= n; i ++ )
	{
		if(ans[i] == 0)
		{
			printf("%d\n",i);
			return 0;
		}
	}
	int s = query(1,n,1);
	if(s > 0)
		printf("%d\n",n + 2);
	else
		printf("%d\n",n + 1);
 } 

相關文章