By Xhr
一道思路很不错的题!
首先这道题是支持离线的,所以我们可以先将所有询问按左端点从小到大排序。
然后这样考虑:
我们可以通过O(n)的方法求出区间[1,i]的mex值。(1≤i≤n)
接着考虑区间[l,r]和[l+1,r]mex值的区别。可以发现如果r≥next[i],两个区间的mex值是相同的。如果是r<next[i]的情况呢?显然只需要将区间内大于a[l]的mex值修改为a[l],即区间取min操作。(其中next[i]表示在点i之后第一个与a[i]相同的点的位置,这个也是可以预处理出的)
于是这道题就转化为在区间内取min操作和单点查询,显然用线段树实现。
Tips:
① 这道题将所有询问排序(离线)和转化为区间修改的方法很巧妙。
② 线段树中的叶子节点表示区间[now,i]的mex值(其中now为当前左端点,i为叶节点对应的位置);线段树中的非叶子节点并没有实际含义,只是为了修改操作的方便。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<cstdlib> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define LL long long #define pa pair<int,int> #define MAXN 200005 #define INF 1000000000 using namespace std; struct tree_type { int l,r,mn; }t[MAXN*4]; struct data { int l,r,num; }b[MAXN]; int n,m,tmp=0,now=1,a[MAXN],f[MAXN],next[MAXN],last[MAXN],ans[MAXN]; bool mark[MAXN]; int read() { int ret=0,flag=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') flag=-1;ch=getchar();} while (ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();} return ret*flag; } void build(int k,int l,int r) { t[k].l=l; t[k].r=r; if (l==r) { t[k].mn=f[l]; return; } t[k].mn=INF; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void pushdown(int k) { if (t[k].mn==INF) return; t[k<<1].mn=min(t[k<<1].mn,t[k].mn); t[k<<1|1].mn=min(t[k<<1|1].mn,t[k].mn); t[k].mn=INF; } void change(int k,int x,int y,int z) { if (t[k].l==x&&t[k].r==y) { t[k].mn=min(t[k].mn,z); return; } pushdown(k); int mid=(t[k].l+t[k].r)>>1; if (mid>=y) change(k<<1,x,y,z); else if (mid+1<=x) change(k<<1|1,x,y,z); else change(k<<1,x,mid,z),change(k<<1|1,mid+1,y,z); } int query(int k,int x) { if (t[k].l==t[k].r) return t[k].mn; pushdown(k); int mid=(t[k].l+t[k].r)>>1; if (x<=mid) return query(k<<1,x); else return query(k<<1|1,x); } bool cmp(data x,data y) { return x.l<y.l; } int main() { memset(mark,false,sizeof(mark)); memset(next,0,sizeof(next)); memset(last,0,sizeof(last)); n=read();m=read(); F(i,1,n) a[i]=read(); F(i,1,n) { mark[a[i]]=true; while (mark[tmp]) tmp++; f[i]=tmp; } build(1,1,n); D(i,n,1) { next[i]=last[a[i]]; last[a[i]]=i; } F(i,1,m) { b[i].l=read(); b[i].r=read(); b[i].num=i; } sort(b+1,b+m+1,cmp); F(i,1,m) { while (now<b[i].l) { if (!next[now]) next[now]=n+1; change(1,now,next[now]-1,a[now]); now++; } ans[b[i].num]=query(1,b[i].r); } F(i,1,m) printf("%d\n",ans[i]); return 0; }