线段树/莫队-区间mex查询 NKOJ4254
题目
给你一个长度为n的数列,元素编号1到n,第i个元素值为Ai。现在有m个形如(L,R)的提问,你需要回答出区间[L,R]的mex值。即求出区间[L,R]中没有出现过的最小的非负整数。
详细见NKOJ4254
总结一下这道题的三种解法
1.莫队分块,参考 NewUser 代码,非常暴力
另两种需要分析一下
提前计算 Mi = mex(1, i) , 1<=i<=n .分析一下的话发现 M 单调不降,再分析一下发现
通过 mex(l, r) 可以得到 mex(l+1, r)
分析一下从被执行 mex 操作的 A[l, r] 中删去一个 A[l] 对整体的影响
先算一下与 A[l] 相等的数在序列中的位置,记为 next[l]
(如果没有这样的数则 next[l] = n+1)
受影响的区间是 M[l+1, next[l]-1] ,对于其中任意一个下标 t
M[t] < A[l] ,M[t]并不受影响
M[t] > A[l] ,M[t]变为A[l]
M[t] = A[l] ,显然不可能呀
即M[t] = min(M[t], A[l])
既然是区间操作那就搞个线段树吧,用 lazy 表示这样的“可能使某个M区间的值变小的A[l]”,叶子节点的 lazy 则表示原来M中的数
好啦然后看一下具体操作,对于询问以左起点为第一关键字排序,然后可得 l1 <= l2 <= l3 ...
用 d 表示当前维护 M 对应 mex 的左起点,初始时d = 1
若 d < l 则对 M[l+1, next[l]-1] 进行修改操作,d = l 时对 r 位置进行查询操作
所以说
2.线段树,参考我的代码吧(笑)
3.据说可以暴力维护 M ,每次从 next[l]-1 往左找到 l+1,如果 M[t]>A[l] 则把 Mt 修改为Al ,否则(Mt < Al)就结束修改;之所以
还可以这样操作是因为序列单调不降,若Mt < Al,则左边的 M[t-1], M[t-2].... <= Mt < Al
线段树代码(我写的)
1 #include <stdio.h> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int _N = 1200005; 7 8 int M[_N], A[_N], fst[_N], nxt[_N], ans[_N]; 9 int n, m; 10 11 struct node { 12 int l, r, mid, lazy; 13 void set_lr(int _l, int _r) { l = _l; r = _r; mid = l+r>>1; return; }; 14 void update(int val) 15 { 16 if (lazy == -1218) { lazy = val; return; } 17 lazy = min(lazy, val); 18 return; 19 } 20 } T[_N]; 21 22 struct qqq { int l, r, id; } Q[_N]; 23 24 bool cmp (const qqq &t1, const qqq &t2) { return t1.l < t2.l; } 25 26 void _build(int p, int l, int r) 27 { 28 T[p].set_lr(l, r), T[p].lazy = -1218; 29 if (l == r) { T[p].lazy = M[l]; return; } 30 _build(p<<1, l, T[p].mid), _build(p<<1|1, T[p].mid+1, r); 31 return; 32 } 33 34 void _pushdown(int p) 35 { 36 T[p<<1].update(T[p].lazy), T[p<<1|1].update(T[p].lazy); 37 T[p].lazy = -1218; 38 return; 39 } 40 41 void _modify(int p, int l, int r, int val) 42 { 43 if (l <= T[p].l && T[p].r <= r) { T[p].update(val); return; } 44 if (l <= T[p].mid && r >= T[p].l) _modify(p<<1, l, r, val); 45 if (l <= T[p].r && r > T[p].mid) _modify(p<<1|1, l, r, val); 46 return; 47 } 48 49 int _query(int p, int pos) 50 { 51 if (T[p].l == T[p].r) return T[p].lazy;; 52 if (T[p].lazy != -1218) _pushdown(p); 53 return (pos <= T[p].mid) ? (_query(p<<1, pos)) : (_query(p<<1|1, pos)); 54 } 55 56 int main() 57 { 58 int d, i; 59 scanf("%d%d", &n, &m); 60 for (i = 1; i <= n; ++i) 61 scanf("%d", &A[i]); 62 for (i = n; i >= 1; --i) 63 nxt[i] = fst[A[i]], fst[A[i]] = i; 64 d = 0; 65 for (i = 1; i <= n; ++i) { 66 if (A[i] == d) while (fst[++d] && fst[d] <= i); 67 M[i] = d; 68 } 69 _build(1, 1, n); 70 for (i = 1; i <= m; ++i) 71 scanf("%d%d", &Q[i].l, &Q[i].r), Q[i].id = i; 72 sort(Q+1, Q+1+m, cmp); 73 d = 1; 74 for (i = 1; i <= m; ++i) { 75 while (d < Q[i].l) { 76 // printf("going to modify [%d, %d]\n", d+1, nxt[d]-1); 77 if (!nxt[d]) nxt[d] = n+1; 78 _modify(1, d+1, nxt[d]-1, A[d]), ++d; 79 } 80 ans[Q[i].id] = _query(1, Q[i].r); 81 } 82 for (i = 1; i <= m; ++i) 83 printf("%d\n", ans[i]); 84 return 0; 85 }