NKOJ 4254 區間MEX (線段樹)
阿新 • • 發佈:2019-02-14
P4254區間MEX
問題描述
給你一個長度為n的數列,元素編號1到n,第i個元素值為Ai。現在有m個形如(L,R)的提問,你需要回答出區間[L,R]的mex值。即求出區間[L,R]中沒有出現過的最小的非負整數。
輸入格式
第一行,兩個整數n和m
第二行,n個空格間隔的整數,表示數列A
接下來m行,每行兩個整數L,R,表示一次詢問
輸出格式
m行,每行一個整數,表示對應詢問的答案。
樣例輸入
7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
樣例輸出
3
0
3
2
4
提示
1<=n,m<=200000
0<=Ai<=200000
1<=L<=R<=n
由於沒有修改,可以考慮離線演算法。先將詢問按照左端點排序。
令
考慮刪掉
如果
那麼區間修改用線段樹來維護,按照左端點升序討論即可。
程式碼:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 200005
#define M 2000005
#define min(a,b) ((a>b)?(b):(a))
using namespace std;
struct node{int id,l,r,ans;}Q[N];
bool cmp(node a,node b)
{return a.l<b.l;}
bool ccp(node a,node b)
{return a.id<b.id;}
int n,m,A[N],B[N],NE[N],LA[N];
bool mark[N];
int ls[M],rs[M],v[M],lazy[M],tot,rt;
int BT(int x,int y)
{
int p=++tot;
lazy[p]=-1;
if(x<y)
{
int mid=x+y>>1;
ls[p]=BT(x,mid);
rs[p]=BT(mid+1,y);
}
else v[p]=B[x];
return p;
}
void PD(int p)
{
int l=ls[p],r=rs[p],d=lazy[p];
lazy[p]=-1;
v[l]=min(v[l],d);
v[r]=min(v[r],d);
if(lazy[l]==-1)lazy[l]=d;
else lazy[l]=min(lazy[l],d);
if(lazy[r]==-1)lazy[r]=d;
else lazy[r]=min(lazy[r],d);
}
void MD(int p,int l,int r,int x,int y,int d)
{
if(lazy[p]!=-1)PD(p);
if(x<=l&&y>=r){lazy[p]=d;v[p]=min(v[p],d);return;}
int mid=l+r>>1;
if(x<=mid&&y>=l)MD(ls[p],l,mid,x,y,d);
if(x<=r&&y>mid)MD(rs[p],mid+1,r,x,y,d);
}
int GA(int p,int l,int r,int k)
{
if(lazy[p]!=-1)PD(p);
if(l==r)return v[p];
int mid=l+r>>1;
if(k<=mid)return GA(ls[p],l,mid,k);
return GA(rs[p],mid+1,r,k);
}
int main()
{
int i,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&A[i]);
for(i=1;i<=m;i++)scanf("%d%d",&Q[i].l,&Q[i].r),Q[i].id=i;
sort(Q+1,Q+m+1,cmp);x=0;
for(i=1;i<=n;i++)
{
mark[A[i]]=1;
while(mark[x])x++;
B[i]=x;
}
for(i=n;i>=1;i--)
{
if(!LA[A[i]])NE[i]=n+1;
else NE[i]=LA[A[i]];
LA[A[i]]=i;
}
rt=BT(1,n);x=1;i=1;
while(i<=m)
{
while(x<Q[i].l)
{
if(x+1<NE[x])MD(rt,1,n,x+1,NE[x]-1,A[x]);
x++;
}
while(x==Q[i].l)
{
Q[i].ans=GA(rt,1,n,Q[i].r);
i++;
}
}
sort(Q+1,Q+m+1,ccp);
for(i=1;i<=m;i++)printf("%d\n",Q[i].ans);
}