Mex
问题提出
有一个长度为nnn的数组{a1,a2,…,an}\{a_1,a_2,…,a_n\}{a1,a2,…,an}。mmm次询问,每次询问一个区间内最小没有出现过的自然数。
题目解答
对1−n1-n1−n这里能够的每个数xxx,都统计出来在数组中出现的位置,并在前补上000,在后补上n+1n+1n+1.
例如数组{1,2,3,2,1}\{1,2,3,2,1\}{1,2,3,2,1},
其中111出现过的位置就是:{0,1,5,6}\{0,1,5,6\}{0,1,5,6}
其中222出现过的位置就是:{0,2,4,6}\{0,2,4,6\}{0,2,4,6}
其中333出现过的位置就是:{0,3,6}\{0,3,6\}{0,3,6}
其中444出现过的位置就是:{0,6}\{0,6\}{0,6}
其中555出现过的位置就是:{0,6}\{0,6\}{0,6}
如果一个自然数xxx没有在一个区间[l,r][l,r][l,r]中出现过,那么必然存在xxx的出现序列中的两个位置p1,p2p_1,p_2p1,p2满足p1<l<r<p2p_1<l<r<p_2p1<l<r<p2.
那么这就变成一个经典的222维数点问题啦!
我们把每个xxx的出现位置序列,相邻两个数并成一个二维数点,插入到线段树中去.
对于每个询问(l,r)(l,r)(l,r)在线段树中找满足p1<l<r<p2p_1<l<r<p_2p1<l<r<p2条件的权值最小的点就可以了.
将所有的询问(l,r)(l,r)(l,r)和数点p1,p2p_1,p_2p1,p2按照第二维排序,从左往右枚举,遇到询问就回答,遇到数点就插入.
排序可以省掉一维.
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)
#define repi(i,a,b) for(int i = a;i >= b;--i)
#define clr(x) memset(x,0,sizeof(x))
#define setinf(x) memset(x,0x3f,sizeof(x))const int N = 200010;
const int inf = 1e9+7;
int n,m;
int a[N];
std::map<int,int> map;struct node{int num;node(int x = inf){num = x;}
}ns[N<<2];struct que{int l,r,id;que(int l = 0,int r = 0,int id = 0) {this->l = l,this->r = r,this->id = id;}bool operator<(const que &q)const{return l < q.l;}
}qs[N],qs2[N<<2];int ans[N];node maintain(node &lch,node &rch) {node res = node();res.num = std::min(lch.num,rch.num);return res;
} void change(int o,int l,int r,int pos,int val) {if(l == r) {if(val < ns[o].num) ns[o].num = val;return ;}int mid = (l + r) >> 1;if(pos <= mid) change(o<<1,l,mid,pos,val);else change(o<<1|1,mid+1,r,pos,val);ns[o] = maintain(ns[o<<1],ns[o<<1|1]);
}node query(int o,int l,int r,int ql,int qr) {if(ql <= l && r <= qr) return ns[o];if(r < ql || qr < l)return node(); int mid = (l + r) >> 1;node lch = query(o<<1,l,mid,ql,qr);node rch = query(o<<1|1,mid+1,r,ql,qr);return maintain(lch,rch);
}void build(int o,int l,int r) {if(l == r) {ns[o] = node();return ;}int mid = (l + r) >> 1;build(o<<1,l,mid);build(o<<1|1,mid+1,r);ns[o] = maintain(ns[o<<1],ns[o<<1|1]);
}int main() {std::ios::sync_with_stdio(false);std::cin >> n >> m;build(1,0,n+1);rep(i,1,n) std::cin >> a[i];int cc = 0;rep(i,1,n){qs2[cc++] = que(map[a[i]],i,a[i]);map[a[i]] = i;}rep(i,0,2*n) {qs2[cc++] = que(map[i],n+1,i);}std::sort(qs2,qs2+cc);rep(i,1,m) {std::cin >> qs[i].l >> qs[i].r;qs[i].id = i;} std::sort(qs+1,qs+1+m);int pos = 0;rep(i,1,m) {while(pos < cc && qs2[pos].l < qs[i].l){change(1,0,n+1,qs2[pos].r,qs2[pos].id);++pos;}node res = query(1,0,n+1,qs[i].r+1,n+1);ans[qs[i].id] = res.num;}rep(i,1,m) {std::cout << ans[i] << std::endl;}}