P4137 Rmq Problem / mex 強制線上做法
阿新 • • 發佈:2021-08-06
區間mex
Problem
給定一個數組\(a\),每次詢問給定一個區間\([l,r]\),求區間\(\operatorname{mex}\)。
\(n \le 2 \times 10 ^ 5,a_i \le 10 ^ 9\)。
Solution
考慮用主席樹做。每個節點記錄它代表的區間權值在當前最早出現的位置。查詢的時候直接在\(Root_r\)上查詢$ < l$的即可。
# include <bits/stdc++.h> using namespace std; const int N = 2e5 + 5; int n,m; int a[N],Root[N],tot = 0; struct node { int mex,l,r; }T[N << 5]; void update(int &root,int pre,int l,int r,int x,int d) { root = ++tot; T[root] = T[pre]; if(l == r) { T[root].mex = d; return; } int mid = (l + r) >> 1; if(x <= mid) update(T[root].l,T[pre].l,l,mid,x,d); if(x > mid) update(T[root].r,T[pre].r,mid + 1,r,x,d); T[root].mex = min(T[T[root].l].mex,T[T[root].r].mex); return; } int query(int root,int l,int r,int k) { if(l == r) return l; int mid = (l + r) >> 1; if(T[T[root].l].mex < k) return query(T[root].l,l,mid,k); else return query(T[root].r,mid + 1,r,k); } int main(void) { scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&a[i]); for(int i = 1; i <= n; i++) { if(a[i] >= n) Root[i] = Root[i - 1]; else update(Root[i],Root[i - 1],1,n + 1,a[i] + 1,i); } while(m--) { int l,r; scanf("%d%d",&l,&r); printf("%d\n",query(Root[r],1,n + 1,l) - 1); } return 0; }