zoukankan      html  css  js  c++  java
  • 线段树/莫队-区间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]
    ", 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
    ", ans[i]);
    84     return 0;
    85 }
    View Code
  • 相关阅读:
    IDEA快捷键
    Win10如何禁止软件运行?win10禁止软件启动的设置方法!禁止人生日历热点快讯的方法
    java反射
    JDBC基础
    mysql基础
    java基础
    Quartz.NET(任务调度)与Topshelf(服务)的综合使用
    【专栏学习】APM——异步编程模型(.NET不推荐)
    中小型研发团队架构实践
    Android 下拉菜单 Spinner 赋值
  • 原文地址:https://www.cnblogs.com/ghcred/p/8244272.html
Copyright © 2011-2022 走看看