P4137 Rmq Problem / mex 可持久化线段树求区间MEX
P4137 Rmq Problem / mex 可持久化线段树求区间MEX
题意
如题,给定\(n\)个数,\(q\)个询问,求\([L,R]\)的MEX
\[1 \leq n \leq1e5\\
1\leq q\leq1e5\\
0 \leq a_i \leq1e9
\]
分析
我们对\([1,r]\)建立可持久化值域线段树,那么\([L,R]\)的MEX等价于第\(r\)棵树上第一个最后出现位置小于\(l\)的值
当然,这还要简单的转化,就是把\(a_i + 1\)也看成权值加进来。
查询就是简单的树上维护最小值二分了
代码
int a[maxn],b[maxn << 1 ],len,idx;
inline int getid(int val){
return lower_bound(b + 1,b + len + 1,val) - b;
}
struct ZXS{
int cnt;
vector<int> mi,L,R,T;
ZXS(int n):cnt(0),mi(n * 44),L(n * 44),R(n * 44),T(n + 5) {}
int build(int l,int r){
int rt = ++cnt;
mi[rt] = 0;
int mid = l + r >> 1;
if(l < r) {
L[rt] = build(l,mid);
R[rt] = build(mid + 1,r);
}
return rt;
}
int update(int pre,int l,int r,int x,int la){
int rt = ++cnt;
L[rt] = L[pre],R[rt] = R[pre];
mi[rt] = mi[pre];
if(l == r) {
mi[rt] = la;
return rt;
}
int mid = l + r >> 1;
if(x <= mid) L[rt] = update(L[pre],l,mid,x,la);
else R[rt] = update(R[pre],mid + 1,r,x,la);
mi[rt] = min(mi[L[rt]],mi[R[rt]]);
return rt;
}
int query(int rt,int l,int r,int x) {
if(l == r) return b[l];
int mid = l + r >> 1;
if(mi[L[rt]] >= x) return query(R[rt],mid + 1,r,x);
else return query(L[rt],l,mid,x);
}
};
int main(){
int n = rd();
int q = rd();
for(int i = 1;i <= n;i++) {
a[i] = rd();
b[++idx] = a[i];
b[++idx] = a[i] + 1;
}
sort(b + 1,b + idx + 1);
len = unique(b + 1,b + idx + 1) - (b + 1);
ZXS seg(n);
seg.T[0] = seg.build(1,len);
for(int i = 1;i <= n;i++){
seg.T[i] = seg.update(seg.T[i - 1],1,len,getid(a[i]),i);
}
while(q--){
int l = rd();
int r = rd();
printf("%d\n",seg.query(seg.T[r],1,len,l));
}
}