zoukankan      html  css  js  c++  java
  • bzoj 3585 mex

    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

    Sample Output

    1
    2
    3
    0
    3

    HINT

    数据规模和约定

      对于100%的数据:

      1<=n,m<=200000

      0<=ai<=109

      1<=l<=r<=n


      对于30%的数据:


      1<=n,m<=1000

    Source

    题目大意

      区间询问mex。

    Solution 1 Mo's Algorithm & Block Division

      区间求mex?不会,直接莫队。

      由于一个数大于等于$n$时无意义,所以按$n$分块,每块记录是否完全被覆盖。

      查询时暴力跳。

      表示数据真水,最开始某个地方的$x$,写成$p$竟然A了。

    Code

     1 /**
     2  * bzoj
     3  * Problem#3585
     4  * Accepted
     5  * Time: 6832ms
     6  * Memory: 5988k 
     7  */
     8 #include <bits/stdc++.h>
     9 using namespace std;
    10 typedef bool boolean;
    11 
    12 const int cs = 500;
    13 
    14 typedef class Query {
    15     public:
    16         int l, r;
    17         int id;
    18 
    19         Query() {    }
    20 
    21         boolean operator < (Query b) const {
    22             if (l / cs  != b.l / cs)    return l < b.l;
    23             return r < b.r;
    24         }
    25 }Query;
    26 
    27 int n, m;
    28 int* ar;
    29 Query* qs;
    30 int exist[200005];
    31 int cover[cs];
    32 int *res;
    33 
    34 inline void init() {
    35     scanf("%d%d", &n, &m);
    36     ar = new int[(n + 1)];
    37     qs = new Query[(m + 1)];
    38        res = new int[(m + 1)];
    39     for (int i = 1; i <= n; i++)
    40         scanf("%d", ar + i);
    41     for (int i = 1; i <= m; i++)
    42         scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].id = i;
    43 }
    44 
    45 inline void update(int p, int sign) {
    46     int x = ar[p];
    47     if (x >= n)    return;
    48     if (!exist[x] && sign == 1)    cover[x / cs]++;
    49     exist[x] += sign;
    50     if (!exist[x] && sign == -1)cover[x / cs]--;
    51 }
    52 
    53 inline void solve() {
    54     sort(qs + 1, qs + m + 1);
    55     int mdzzl = 1, mdzzr = 0;
    56     for (int i = 1; i <= m; i++) {
    57         while (mdzzr < qs[i].r)    update(++mdzzr, 1);
    58         while (mdzzr > qs[i].r)    update(mdzzr--, -1);
    59         while (mdzzl < qs[i].l)    update(mdzzl++, -1);
    60         while (mdzzl > qs[i].l)    update(--mdzzl, 1);
    61 
    62         for (int j = 0; j < cs; j++) {
    63             if (cover[j] < cs) {
    64                 int k = j * cs;
    65                 while (exist[k])    k++;
    66                 res[qs[i].id] = k;
    67                 break;
    68             }
    69         }
    70     }
    71 
    72     for (int i = 1; i <= m; i++)
    73         printf("%d
    ", res[i]);
    74 }
    75 
    76 int main() {
    77     init();
    78     solve();
    79     return 0;
    80 }
    分块&莫队

    Solution 2 Segment Tree

      假设你通过某种方式求出了$[1, i]$的答案。

      考虑删掉位置1,那么位置上的数到下一次它出现之前都可以用来更新答案。

      于是线段树区间修改,单点查询,做完了。

    Code

      1 /**
      2  * bzoj
      3  * Problem#3585
      4  * Accepted
      5  * Time: 4436ms
      6  * Memory: 15184k
      7  */
      8 #include <bits/stdc++.h>
      9 using namespace std;
     10 typedef bool boolean;
     11 
     12 #define smin(_a, _b) (_a > _b) ? (_a = _b) : (0)
     13 
     14 typedef class Query {
     15     public:
     16         int l, r, id, next;
     17 }Query;
     18 
     19 typedef class SegTreeNode {
     20     public:
     21         int val;
     22         SegTreeNode *l, *r;
     23 
     24         SegTreeNode():l(NULL), r(NULL) {    }
     25 }SegTreeNode;
     26 
     27 SegTreeNode pool[500000];
     28 SegTreeNode* top = pool;
     29 
     30 SegTreeNode* newnode(int val) {
     31     top->val = val;
     32     return top++;
     33 }
     34 
     35 typedef class SegTree {
     36     public:
     37         SegTreeNode* rt;
     38 
     39         SegTree() {    }
     40         SegTree(int n, int* f) {
     41             build(rt, 1, n, f);
     42         }
     43 
     44         void build(SegTreeNode*& p, int l, int r, int* f) {
     45             p = newnode(200000);
     46             if (l == r) {
     47                 p->val = f[l];
     48                 return;
     49             }
     50             int mid = (l + r) >> 1;
     51             build(p->l, l, mid, f);
     52             build(p->r, mid + 1, r, f);
     53         }
     54 
     55         void update(SegTreeNode* p, int l, int r, int ql, int qr, int val) {
     56             if (l == ql && r == qr) {
     57                 smin(p->val, val);
     58                 return;
     59             }
     60             int mid = (l + r) >> 1;
     61             if (qr <= mid)
     62                 update(p->l, l, mid, ql, qr, val);
     63             else if (ql > mid)
     64                 update(p->r, mid + 1, r, ql, qr, val);
     65             else {
     66                 update(p->l, l, mid, ql, mid, val);
     67                 update(p->r, mid + 1, r, mid + 1, qr, val);
     68             }
     69         }
     70 
     71         int query(SegTreeNode* p, int l, int r, int idx) {
     72             if (l == idx && r == idx)
     73                 return p->val;
     74             int mid = (l + r) >> 1, rt = p->val, a = 211985;
     75             if (idx <= mid)
     76                 a = query(p->l, l, mid, idx);
     77             else
     78                 a = query(p->r, mid + 1, r, idx);
     79             return (a < rt) ? (a) : (rt);
     80         }
     81 }SegTree;
     82 
     83 int n, m;
     84 int *ar, *suf;
     85 int *last, *res;
     86 Query *qs;
     87 int *h, *f;
     88 SegTree st;
     89 boolean *exist;
     90 
     91 inline void init() {
     92     scanf("%d%d", &n, &m);
     93     h = new int[(n + 1)];
     94     f = new int[(n + 1)];
     95     ar = new int[(n + 1)];
     96     suf = new int[(n + 1)];
     97     res = new int[(m + 1)];
     98     qs = new Query[(m + 1)];
     99     last = new int[(n + 1)];
    100     exist = new boolean[(n + 1)];
    101     fill(h, h + n + 1, 0);
    102     fill(suf, suf + n + 1, n + 1);
    103     fill(last, last + n + 1, 0);
    104     fill(exist, exist + n + 1, false);
    105     for (int i = 1, x; i <= n; i++) {
    106         scanf("%d", ar + i);
    107         if (ar[i] >= n)    continue;
    108         x = ar[i];
    109         if (last[x])
    110             suf[last[x]] = i;
    111         last[x] = i;
    112     }
    113     for (int i = 1; i <= m; i++) {
    114         scanf("%d%d", &qs[i].l, &qs[i].r);
    115         qs[i].id = i, qs[i].next = h[qs[i].l], h[qs[i].l] = i;
    116     }
    117 }
    118 
    119 inline void prepare() {
    120     int p = 0;
    121     for (int i = 1; i <= n; i++) {
    122         if (ar[i] < n)
    123             exist[ar[i]] = true;
    124         while (exist[p])    p++;
    125         f[i] = p;
    126     }
    127     st = SegTree(n, f);
    128 }
    129 
    130 inline void solve() {
    131     for (int i = 1; i <= n; i++) {
    132         for (int j = h[i]; j; j = qs[j].next)
    133             res[qs[j].id] = st.query(st.rt, 1, n, qs[j].r);
    134         if (ar[i] < n) {
    135             st.update(st.rt, 1, n, i, suf[i] - 1, ar[i]);
    136         }
    137     }
    138     for (int i = 1; i <= m; i++)
    139         printf("%d
    ", res[i]);
    140 }
    141 
    142 int main() {
    143     init();
    144     prepare();
    145     solve();
    146     return 0;
    147 }
  • 相关阅读:
    BZOJ3065(替罪羊树套线段树)
    BZOJ3052(树上带修莫队)
    BZOJ1095(动态点分治+堆)
    NOIWC颓废记
    BZOJ2125 最短路
    Simpson积分(BZOJ2178)
    BZOJ4555 [Tjoi2016&Heoi2016]求和
    NTT+多项式求逆+多项式开方(BZOJ3625)
    Miller-Rabin,Pollard-Rho(BZOJ3667)
    单纯形求解线性规划(BZOJ1061)
  • 原文地址:https://www.cnblogs.com/yyf0309/p/8470652.html
Copyright © 2011-2022 走看看