BZOJ 3585: mex
3585: mex
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 778 Solved: 416
[Submit][Status][Discuss]
Description
有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。
Input
第一行n,m。
第二行为n个数。
从第三行开始,每行一个询问l,r。
Output
一行一个数,表示每个询问的答案。
Sample Input
5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
Sample Output
1
2
3
0
3
2
3
0
3
HINT
数据规模和约定
对于100%的数据:
1<=n,m<=200000
0<=ai<=109
1<=l<=r<=n
对于30%的数据:
1<=n,m<=1000
Source
先处理出以1为左区间,i为右区间的所有mex值,发现是单调的。然后离线询问,按照左端点排序。如果当前询问和mex的左区间一样,直接取出答案,否则去掉左区间的数字,更新mex数组。更新时倒着更新就可以了。
1 #include <bits/stdc++.h> 2 3 const int mxn = 200005; 4 5 int n, m, num[mxn], nxt[mxn], lst[mxn], mex[mxn], vis[mxn], ans[mxn]; 6 7 struct query { 8 int l, r, t; 9 }q[mxn]; 10 11 inline bool cmp(const query &a, const query &b) 12 { 13 return a.l < b.l; 14 } 15 16 signed main(void) 17 { 18 scanf("%d%d", &n, &m); 19 20 for (int i = 1; i <= n; ++i) 21 { 22 scanf("%d", num + i); 23 if (num[i] > n) 24 num[i] = n; 25 } 26 27 for (int i = 0; i <= n; ++i) 28 lst[i] = n + 1; 29 30 for (int i = n; i >= 1; --i) 31 nxt[i] = lst[num[i]], lst[num[i]] = i; 32 33 for (int i = 1; i <= n; ++i) 34 { 35 mex[i] = mex[i - 1]; 36 vis[num[i]] = true; 37 while (vis[mex[i]]) 38 ++mex[i]; 39 } 40 41 for (int i = 1; i <= m; ++i) 42 scanf("%d%d", &q[i].l, &q[i].r), q[i].t = i; 43 44 std::sort(q + 1, q + m + 1, cmp); 45 46 int left = 1; 47 48 for (int i = 1; i <= m; ++i) 49 { 50 while (left < q[i].l) 51 { 52 int t = nxt[left]; 53 int p = num[left]; 54 for (int j = t - 1; j > left; --j) 55 { 56 if (mex[j] <= p)break; 57 else mex[j] = p; 58 } 59 ++left; 60 } 61 62 ans[q[i].t] = mex[q[i].r]; 63 } 64 65 for (int i = 1; i <= m; ++i) 66 printf("%d\n", ans[i]); 67 }
@Author: YouSiki