[BZOJ 3585] mex
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=3585
[算法]
两种做法 :
1. 莫队 , 时间复杂度 : O(Nsqrt(N)) (sqrt表示开根号)
2. 可持久化线段树 , 我们只需在第i棵线段树上维护每个数最晚出现的时间 , 查询时在线段树上二分即可 , 时间复杂度 :O(NlogN)
[代码]
莫队 :
#include<bits/stdc++.h> using namespace std; #define MAXN 200010 const int inf = 2e9; struct query { int l , r; int id; } q[MAXN]; int n , m , mn = 0; int a[MAXN] , cnt[MAXN] , ans[MAXN] , belong[MAXN]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline bool cmp(query a , query b) { return belong[a.l] == belong[b.l] ? a.r < b.r : a.l < b.l; } inline void add(int idx) { if (a[idx] >= MAXN) return; ++cnt[a[idx]]; while (cnt[mn] > 0) ++mn; } inline void dec(int idx) { if (a[idx] >= MAXN) return; --cnt[a[idx]]; if (!cnt[a[idx]]) chkmin(mn , a[idx]); } int main() { read(n); read(m); for (int i = 1; i <= n; i++) read(a[i]); for (int i = 1; i <= m; i++) { read(q[i].l); read(q[i].r); q[i].id = i; } int block = sqrt(n); for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1; sort(q + 1 , q + m + 1 , cmp); int l = q[1].l , r = q[1].l - 1; for (int i = 1; i <= m; i++) { while (r < q[i].r) { add(r + 1); r++; } while (r > q[i].r) { dec(r); r--; } while (l < q[i].l) { dec(l); l++; } while (l > q[i].l) { add(l - 1); l--; } ans[q[i].id] = mn; } for (int i = 1; i <= m; i++) printf("%d\n" , ans[i]); return 0; }
可持久化线段树 :
#include<bits/stdc++.h> using namespace std; #define N 200010 const int inf = 2e9; int n , m , idx; int v[N * 40] , lson[N * 40] , rson[N * 40] , root[N] , a[N]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void build(int &k , int l , int r) { k = ++idx; v[k] = -inf; if (l == r) return; int mid = (l + r) >> 1; build(lson[k] , l , mid); build(rson[k] , mid + 1 , r); } inline void modify(int &k , int old , int l , int r , int pos , int val) { k = ++idx; lson[k] = lson[old] , rson[k] = rson[old]; v[k] = v[old]; if (l == r) { v[k] = val; return; } int mid = (l + r) >> 1; if (mid >= pos) modify(lson[k] , lson[k] , l , mid , pos , val); else modify(rson[k] , rson[k] , mid + 1 , r , pos , val); v[k] = min(v[lson[k]] , v[rson[k]]); } inline int query(int k , int l , int r , int t) { if (l == r) return l; int mid = (l + r) >> 1; if (v[lson[k]] < t) return query(lson[k] , l , mid , t); else return query(rson[k] , mid + 1 , r , t); } int main() { read(n); read(m); for (int i = 1; i <= n; i++) read(a[i]); build(root[0] , 0 , N - 1); for (int i = 1; i <= n; i++) { if (a[i] < N) modify(root[i] , root[i - 1] , 0 , N - 1 , a[i] , i); else root[i] = root[i - 1]; } for (int i = 1; i <= m; i++) { int l , r; read(l); read(r); printf("%d\n" , query(root[r] , 0 , N - 1 , l)); } return 0; }