题意:给你一个长度为n的数列,元素编号1到n,第i个元素值为Ai。现在有m个形如(L,R)的提问,你需要回答出区间[L,R]的mex值。即求出区间[L,R]中没有出现过的最小的非负整数。
题解:
由于没有修改,可以考虑离线算法。先将询问按照左端点排序。
令S[i]表示区间[1,i]的MEX值MEX值,容易发现S[i]单调不降,并且可以O(n)的处理出来S数组。那么左端点为1的询问都可以处理,然后考虑如何处理左端点为2时
考虑删掉A[1]对S数组的影响,那么令x=A[1]下一次出现的位置x=A[1]下一次出现的位置,那么S[x]以后肯定不会受到影响,而对于x之前的S[k]
如果S[k]>A[i],那么S[k]=A[i],否则不变
那么区间修改用线段树来维护,按照左端点升序讨论即可,线段树维护一段区间的mex,当修改值比当前值小,则修改。
/*
*线段树 区间mex 离线
*/
#include <bits/stdc++.h>
#define FOR(i,s,t) for(int i=(s);i<=(t);i++)
#define ROF(i,s,t) for(int i=(s);i>=(t);i--)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 2e5 + 6;
const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int readInt(){
int x=0;
bool sign=false;
char c=getchar();
while(!isdigit(c)){
sign=c=='-';
c=getchar();
}
while(isdigit(c)){
x=x*10+c-'0';
c=getchar();
}
return sign?-x:x;
}
ll readLong(){
ll x=0;
bool sign=false;
char c=getchar();
while(!isdigit(c)){
sign=c=='-';
c=getchar();
}
while(isdigit(c)){
x=x*10+c-'0';
c=getchar();
}
return sign?-x:x;
}
string readString(){
string s;
char c=getchar();
while(isspace(c)){
c=getchar();
}
while(!isspace(c)){
s+=c;
c=getchar();
}
return s;
}
int n, m;
int mex[maxn], nxt[maxn], mark[maxn],last[maxn], a[maxn],ans[maxn];
int M[maxn<<2], tag[maxn << 2];
struct Ques{
int l, r, id;
bool operator<(const Ques A) const{
return l < A.l;
}
}Q[maxn];
void gather(int p ){
M[p] = min(M[p<<1], M[p<<1|1]);
}
void build(int p, int l, int r){
if (l == r){
M[p] = mex[l];
return;
}
int mid = (l + r) / 2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
gather(p);
}
void push(int p){
if (tag[p] > 0){
tag[p<<1] = min(tag[p<<1], tag[p]);
tag[p<<1|1] = min(tag[p<<1|1],tag[p]);
M[p<<1|1] = min(M[p<<1|1],tag[p]);
M[p<<1] = min(M[p<<1], tag[p]);
tag[p] = -1;
}
}
void modify(int p, int l, int r, int ql, int qr, int val){
if (l > qr || r < ql) return;
if (ql <= l && r <= qr){
if (tag[p] == -1) tag[p] = val;
else tag[p] = min(tag[p], val);
M[p] = min(M[p], val);
return ;
}
push(p);
int mid = (l + r) / 2;
modify(p << 1, l , mid, ql , qr, val);
modify(p << 1|1, mid+1,r, ql, qr, val);
gather(p);
}
int query(int p, int l ,int r, int pos){
if (l == r){
if (l == pos)
return M[p];
}
push(p);
int mid = (l + r) / 2;
int ans = 0;
if (pos <= mid) {
ans = query(p<<1, l ,mid, pos);
}else ans = query(p<<1|1,mid+1,r,pos);
gather(p);
return ans;
}
int main(){
n = readInt();
m = readInt();
FOR(i,1,n) a[i] = readInt();
FOR(i,1,m){
Q[i].l = readInt();
Q[i].r = readInt();
Q[i].id = i;
}
sort(Q+1, Q+1+m);
ROF(i,n,1){
if (!last[a[i]]) nxt[i] = n+1;
else nxt[i] = last[a[i]];
last[a[i]] = i;
}
int j = 0;
FOR(i,1,n){
mark[a[i]] = 1;
while (1){
if (!mark[j]) break;
j++;
}
mex[i] = j;
}
memset(tag, -1,sizeof(tag));
memset(M,inf,sizeof(M));
build(1,1,n);
j = 1;
FOR(i,1,n) cout << nxt[i] << " " ;
FOR(i,1,m){
while (Q[j].l == i){
ans[Q[j].id] = query(1,1,n,Q[j].r);
//cout << ans[Q[j].id] << endl;
j++;
}
modify(1,1,n,i,nxt[i]-1,a[i]);
}
FOR(i,1,m){
cout << ans[i] << " ";
}
return 0;
}