线段树/莫队-区间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 }
View Code

 

posted @ 2018-01-08 18:52  derchg  阅读(819)  评论(1编辑  收藏  举报