區間mex問題,能夠使用經典的記錄上一次位置以後再上主席樹解決。git
不過主席樹好像不是很好寫哈,那咱們寫莫隊吧數組
考慮每一次維護什麼東西,首先記一個答案,同時開一個數組記錄一下每個數出現的次數。spa
而後些比較顯然的性質:若是加入一個數時,答案只會增長;一樣的刪除一個數時,答案只會減少code
利用好這些性質咱們就愉快地上莫隊便可不過複雜度很迷,轉移的時候只能近似\(O(1)\)it
CODEio
#include<cstdio> #include<cctype> #include<cmath> #include<algorithm> using namespace std; const int N=200005; struct data { int l,r,id; }q[N]; int a[N],cnt[N],ans[N],n,m,size,blk[N],res,L,R; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); } inline bool cmp(data a,data b) { return blk[a.l]<blk[b.l]||(blk[a.l]==blk[b.l]&&(blk[a.l]&1?a.r<b.r:a.r>b.r)); } inline int min(int a,int b) { return a<b?a:b; } inline void add(int col) { ++cnt[col]; if (res<col) return; while (cnt[res]) ++res; } inline void del(int col) { if (!(--cnt[col])) res=min(res,col); } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); read(m); size=sqrt(n); for (i=1;i<=n;++i) read(a[i]),a[i]=min(a[i],n+1),blk[i]=(i-1)/size+1; for (i=1;i<=m;++i) read(q[i].l),read(q[i].r),q[i].id=i; sort(q+1,q+m+1,cmp); L=q[1].l; R=q[1].r; for (i=L;i<=R;++i) add(a[i]); ans[q[1].id]=res; for (i=2;i<=m;++i) { while (L>q[i].l) add(a[--L]); while (L<q[i].l) del(a[L++]); while (R<q[i].r) add(a[++R]); while (R>q[i].r) del(a[R--]); ans[q[i].id]=res; } for (i=1;i<=m;++i) write(ans[i]),putchar('\n'); return 0; }