luogu P4137 Rmq Problem / mex

区间求 mex 问题。

对序列建一棵以权值为下标的主席树。每个节点记录:当前区域内每个权值的前一个出现位置的最小值。查询 ([l,r]) 内的 mex 时拿出 (r) 这棵线段树,在上面操作:如果左边区间有最小值小于 (l),那么递归到左区间,否则递归进入右区间。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N=200009;
int n,m,a[N],pool,rt[N];
struct Tree
{
	int l,r,Last;
	#define l(x) b[x].l
	#define r(x) b[x].r
	#define Last(x) b[x].Last
}b[N*32];

void Newpoint(int &k,int last,int l,int r,int x,int qwq)
{
	k=++pool;
	b[k]=b[last];
	if(l==r)
	{
		Last(k)=qwq;
		return;
	}
	int mid=l+r>>1;
	if(mid>=x)
		Newpoint(l(k),l(last),l,mid,x,qwq);
	else
		Newpoint(r(k),r(last),mid+1,r,x,qwq);
	Last(k)=min(Last(l(k)),Last(r(k)));
}

void init()
{
	scanf("%d %d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]),a[i]=a[i]>n?n:a[i];
	for (int i=1;i<=n;i++)
		Newpoint(rt[i],rt[i-1],0,n,a[i],i);
}

int Query(int k,int l,int r,int x)
{
	if(l==r)
		return l;
	int mid=l+r>>1;
	if(Last(l(k))>=x)
		return Query(r(k),mid+1,r,x);
	return Query(l(k),l,mid,x);
}

void work()
{
	int x,y;
	while(m--)
	{
		scanf("%d %d",&x,&y);
		printf("%d
",Query(rt[y],0,n,x));
	}
}

int main()
{
	init();
	work();
	return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
原文地址:https://www.cnblogs.com/With-penguin/p/12839479.html