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\n",Query(rt[y],0,n,x));
}
}
int main()
{
init();
work();
return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!