Loading

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));
	}
}
posted @ 2021-03-06 10:59  MQFLLY  阅读(73)  评论(0编辑  收藏  举报