洛谷 P4137 Rmq Problem/mex 题解

题面

首先,由于本人太菜,不会莫队,所以先采用主席树的做法;

离散化是必须环节,否则动态开点线段数都救不了你;

我们对于每个元素i,插入到1~(i-1)的主席树中,第i颗线段树(权值线段树)对于一个区间[l,r]维护的便是原序列1~i中的所有属于[l,r]的元素出现的最后位置的最小值;

当我们查询[x,y]时,我们查询第y颗线段树,找到第一个位置使得(出现的最后位置的最小值)比(x)要小

然后恢复离散化之前的数值,然后输出;

#include <bits/stdc++.h>
#define inc(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
int n,m;
int a[300010];
int tot;
class node{
	public:
	int lson,rson;
	int last;
}tree[6000010];
int lisan,tt[400010],root[300010];
int change(int pre,int l,int r,int goal,int v)
{
	int now=++tot;
	tree[now].lson=tree[pre].lson;
	tree[now].rson=tree[pre].rson;
	if(l==r){
		tree[tot].last=v;
		return now;
	}		
	int mid=(l+r)/2;
	if(goal<=mid) tree[now].lson=change(tree[pre].lson,l,mid,goal,v);
	else tree[now].rson=change(tree[pre].rson,mid+1,r,goal,v);
	tree[now].last=min(tree[tree[now].lson].last,tree[tree[now].rson].last);
	return now;
}
int query(int now,int l,int r,int goal)
{
	if(l==r) return tt[l];
	int mid=(l+r)/2;
	if(tree[tree[now].lson].last>=goal) return query(tree[now].rson,mid+1,r,goal);
	else return query(tree[now].lson,l,mid,goal);
}
int main(){
	scanf("%d%d",&n,&m);
	tt[++lisan]=0;
	inc(i,1,n){
		scanf("%d",&a[i]);
		tt[++lisan]=a[i]; tt[++lisan]=a[i]+1;
	}
	sort(tt+1,tt+1+lisan);
	lisan=unique(tt+1,tt+1+lisan)-tt-1;
	inc(i,1,n){
		a[i]=lower_bound(tt+1,tt+1+lisan,a[i])-tt;
		root[i]=tot+1;
		change(root[i-1],1,lisan,a[i],i);
	}
	inc(i,1,m){
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",query(root[y],1,lisan,x));
	}
}

 或许以后会更新一篇莫队的做法

猜你喜欢

转载自www.cnblogs.com/kamimxr/p/12037115.html