bzoj 3585 mex - 线段树 - 分块 - 莫队算法
2018-02-25 21:10
302 查看
Description
有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。Input
第一行n,m。第二行为n个数。
从第三行开始,每行一个询问l,r。
Output
一行一个数,表示每个询问的答案。Sample Input
5 52 1 0 2 1
3 3
2 3
2 4
1 2
3 5
Sample Output
12
3
0
3
HINT
数据规模和约定对于100%的数据:
1<=n,m<=200000
0<=ai<=109
1<=l<=r<=n
对于30%的数据:
1<=n,m<=1000
Source
By 佚名提供题目大意
区间询问mex。
Solution 1 Mo's Algorithm & Block Division
区间求mex?不会,直接莫队。由于一个数大于等于$n$时无意义,所以按$n$分块,每块记录是否完全被覆盖。
查询时暴力跳。
表示数据真水,最开始某个地方的$x$,写成$p$竟然A了。
Code
/** * bzoj * Problem#3585 * Accepted * Time: 6832ms * Memory: 5988k */ #include <bits/stdc++.h> using namespace std; typedef bool boolean; const int cs = 500; typedef class Query { public: int l, r; int id; Query() { } boolean operator < (Query b) const { if (l / cs != b.l / cs) return l < b.l; return r < b.r; } }Query; int n, m; int* ar; Query* qs; int exist[200005]; int cover[cs]; int *res; inline void init() { scanf("%d%d", &n, &m); ar = new int[(n + 1)]; qs = new Query[(m + 1)]; res = new int[(m + 1)]; for (int i = 1; i <= n; i++) scanf("%d", ar + i); for (int i = 1; i <= m; i++) scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].id = i; } inline void update(int p, int sign) { int x = ar[p]; if (x >= n) return; if (!exist[x] && sign == 1) cover[x / cs]++; exist[x] += sign; if (!exist[x] && sign == -1)cover[x / cs]--; } inline void solve() { sort(qs + 1, qs + m + 1); int mdzzl = 1, mdzzr = 0; for (int i = 1; i <= m; i++) { while (mdzzr < qs[i].r) update(++mdzzr, 1); while (mdzzr > qs[i].r) update(mdzzr--, -1); while (mdzzl < qs[i].l) update(mdzzl++, -1); while (mdzzl > qs[i].l) update(--mdzzl, 1); for (int j = 0; j < cs; j++) { if (cover[j] < cs) { int k = j * cs; while (exist[k]) k++; res[qs[i].id] = k; break; } } } for (int i = 1; i <= m; i++) printf("%d\n", res[i]); } int main() { init(); solve(); return 0; }
分块&莫队
Solution 2 Segment Tree
假设你通过某种方式求出了$[1, i]$的答案。考虑删掉位置1,那么位置上的数到下一次它出现之前都可以用来更新答案。
于是线段树区间修改,单点查询,做完了。
Code
/** * bzoj * Problem#3585 * Accepted * Time: 4436ms * Memory: 15184k */ #include <bits/stdc++.h> using namespace std; typedef bool boolean; #define smin(_a, _b) (_a > _b) ? (_a = _b) : (0) typedef class Query { public: int l, r, id, next; }Query; typedef class SegTreeNode { public: int val; SegTreeNode *l, *r; SegTreeNode():l(NULL), r(NULL) { } }SegTreeNode; SegTreeNode pool[500000]; SegTreeNode* top = pool; SegTreeNode* newnode(int val) { top->val = val; return top++; } typedef class SegTree { public: SegTreeNode* rt; SegTree() { } SegTree(int n, int* f) { build(rt, 1, n, f); } void build(SegTreeNode*& p, int l, int r, int* f) { p = newnode(200000); if (l == r) { p->val = f[l]; return; } int mid = (l + r) >> 1; build(p->l, l, mid, f); build(p->r, mid + 1, r, f); } void update(SegTreeNode* p, int l, int r, int ql, int qr, int val) { if (l == ql && r == qr) { smin(p->val, val); return; } int mid = (l + r) >> 1; if (qr <= mid) update(p->l, l, mid, ql, qr, val); else if (ql > mid) update(p->r, mid + 1, r, ql, qr, val); else { update(p->l, l, mid, ql, mid, val); update(p->r, mid + 1, r, mid + 1, qr, val); } } int query(SegTreeNode* p, int l, int r, int idx) { if (l == idx && r == idx) return p->val; int mid = (l + r) >> 1, rt = p->val, a = 211985; if (idx <= mid) a = query(p->l, l, mid, idx); else a = query(p->r, mid + 1, r, idx); return (a < rt) ? (a) : (rt); } }SegTree; int n, m; int *ar, *suf; int *last, *res; Query *qs; int *h, *f; SegTree st; boolean *exist; inline void init() { scanf("%d%d", &n, &m); h = new int[(n + 1)]; f = new int[(n + 1)]; ar = new int[(n + 1)]; suf = new int[(n + 1)]; res = new int[(m + 1)]; qs = new Query[(m + 1)]; last = new int[(n + 1)]; exist = new boolean[(n + 1)]; fill(h, h + n + 1, 0); fill(suf, suf + n + 1, n + 1); fill(last, last + n + 1, 0); fill(exist, exist + n + 1, false); for (int i = 1, x; i <= n; i++) { scanf("%d", ar + i); if (ar[i] >= n) continue; x = ar[i]; if (last[x]) suf[last[x]] = i; last[x] = i; } for (int i = 1; i <= m; i++) { scanf("%d%d", &qs[i].l, &qs[i].r); qs[i].id = i, qs[i].next = h[qs[i].l], h[qs[i].l] = i; } } inline void prepare() { int p = 0; for (int i = 1; i <= n; i++) { if (ar[i] < n) exist[ar[i]] = true; while (exist[p]) p++; f[i] = p; } st = SegTree(n, f); } inline void solve() { for (int i = 1; i <= n; i++) { for (int j = h[i]; j; j = qs[j].next) res[qs[j].id] = st.query(st.rt, 1, n, qs[j].r); if (ar[i] < n) { st.update(st.rt, 1, n, i, suf[i] - 1, ar[i]); } } for (int i = 1; i <= m; i++) printf("%d\n", res[i]); } int main() { init(); prepare(); solve(); return 0; }
相关文章推荐
- BZOJ 3585 mex 莫队算法+分块
- BZOJ 3585 mex 莫队算法+分块
- 【莫队算法】【权值分块】bzoj3585 mex
- BZOJ 3339/3585 Rmq Problem/mex 莫队算法
- BZOJ_3585_mex && BZOJ_3339_Rmq Problem_莫队+分块
- BZOJ 3585: mex|莫队算法
- [BZOJ 3585] mex 【莫队+分块】
- [莫队] [分块] [BZOJ3585] mex
- 【莫队算法】【权值分块】bzoj3809 Gty的二逼妹子序列
- 【BZOJ-3809】Gty的二逼妹子序列 分块 + 莫队算法
- 【莫队算法】【权值分块】bzoj3236 [Ahoi2013]作业
- [bzoj3339]Rmq Problem||[bzoj3585]mex_线段树
- 【莫队算法】【权值分块】bzoj3920 Yuuna的礼物
- 【DFS序】【莫队算法】【权值分块】bzoj2809 [Apio2012]dispatching
- 【BZOJ3809/3236】Gty的二逼妹子序列 [Ahoi2013]作业 莫队算法+分块
- 【BZOJ3809】Gty的二逼妹子序列【莫队算法】【分块】
- 【BZOJ3585/3339】mex 莫队算法+分块
- 【BZOJ-2453&2120】维护队列&数颜色 分块 + 带修莫队算法
- 【DFS序】【莫队算法】【权值分块】bzoj1803 Spoj1487 Query on a tree III
- 【莫队算法】【权值分块】bzoj2223 [Coci 2009]PATULJCI