zoukankan      html  css  js  c++  java
  • HDU6756 Finding a MEX

    原题链接

    看到(operatorname{mex}),一个显然的想法就是根号分治。我们设(d_u)为点(u)的度数,再设一个合适正整数(L),代表根号分治的临界值。将所有的点分为两个集合(S_1,S_2),使得(forall uin S_1,d_ule L;forall uin S_2,d_u>L)。有一个显然的性质是(|S_2|le iglfloor dfrac{2 imes n}{L}ig floor)

    先考虑查询。对于所有(S_1)中的点,因其邻居的个数最多是(L),所以珂以暴力枚举邻居算(operatorname{mex})。这个算法是珂以做到(O(L))的(答案输出的(operatorname{mex})的最大值只能是(n),所以你珂以把所有大于(n)的数设置成(n))。对于所有(S_2)中的点,你就必须要对每个(S_2)中的点用一个奇技淫巧的数据结构来维护了。这个数据结构必须要支持全局查询(operatorname{mex})

    先不谈这个数据结构要实现哪些东西,我们来看看修改。修改是单点修改。一个点的修改只会影响到它周边邻居的答案。设点(u)的邻居的集合为(C_u)。对于集合(S_1cap C_u)中的所有点,珂以不用管它们,因为我们在询问时是暴力枚举计算的。所以我们只要考虑集合(S_2cap C_u)中的所有点,这些点的个数最多也只有(iglfloor dfrac{2 imes n}{L}ig floor)个。所以我们珂以暴力枚举这样的邻居,然后对于每一个邻居,用维护它的那个数据结构来修改。具体来说就是在这个数据结构中删除原有的数,再插入新添加的数。

    所以这个数据结构要支持的就是:1. 插入; 2. 删除; 3. 查询全局(operatorname{mex})。那么问题来了,这个数据结构是啥呢?显然平衡树啊!每个节点维护两个值:(val, cnt)。这样询问时就直接二分,判断ls->size是否等于this->cnt即珂。

    所以查询时的时间复杂度为(O(L+log n)),修改的时间复杂度为(O(iglfloor dfrac{2 imes n}{L}ig floor log n))。显然,由均值不等式,当(L)(sqrt {2 imes nlog n})时,时间复杂度取到最优值为(O(nsqrt{nlog n}))。(然后窝这个复杂度跑了(655)ms,勇获rnk(2),吊打了一堆(O(nsqrt{nlog n}))(O(nsqrt{n}))的,而且还没开Ofast)。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    constexpr int _I_Buffer_Size = 32 << 20;
    static char _I_Buffer[_I_Buffer_Size];
    char *_I_pos = _I_Buffer;
    void read(int32_t *n) {
      while (*_I_pos < 48) _I_pos++;
      *n = *_I_pos++ - '0';
      while (*_I_pos > 47)
        *n = *n * 10 + (*_I_pos++ - '0');
    }
    
    constexpr int Maxn = 1e5 + 5, BL = 1024;
    
    int n, m, q;
    int a[Maxn];
    vector<int> g[Maxn];
    int deg[Maxn];
    __attribute__((__always_inline__)) __inline
    void add_edge(int eu, int ev) {
      g[eu].push_back(ev), deg[ev]++;
    }
    bool appear[Maxn];
    
    namespace treap {
      constexpr int Maxs = ::Maxn * 127;
      static mt19937 rng(40113143); // 20051212 + 20060617 + 1314
      int ls[Maxs], rs[Maxs], fix[Maxs], size[Maxs], tot;
      int val[Maxs], cnt[Maxs];
      __attribute__((__always_inline__)) __inline
      void init_treap() {
        tot = 0;
        ls[0] = rs[0] = 0;
        size[0] = 0, fix[0] = 0;
        val[0] = cnt[0] = 0;
      }
      __attribute__((__always_inline__)) __inline
      int newnode(int v) {
        ++tot;
        ls[tot] = rs[tot] = 0;
        fix[tot] = rng();
        size[tot] = 1;
        val[tot] = v;
        cnt[tot] = 1;
        return tot;
      }
      __attribute__((__always_inline__)) __inline
      void pushup(int p) {
        size[p] = size[ls[p]] + size[rs[p]] + 1;
      }
      int join(int l, int r) {
        if (!l || !r) return l | r;
        if (fix[l] < fix[r]) {
          rs[l] = join(rs[l], r);
          pushup(l);
          return l;
        }
        else {
          ls[r] = join(l, ls[r]);
          pushup(r);
          return r;
        }
      }
      void split_s(int p, int s, int &l, int &r) {
        if (!p) l = r = 0;
        else {
          int lsize = size[ls[p]] + 1;
          if (lsize <= s) {
            l = p;
            split_s(rs[p], s - lsize, rs[l], r);
            pushup(l);
          }
          else {
            r = p;
            split_s(ls[p], s, l, ls[r]);
            pushup(r);
          }
        }
      }
      void split_v(int p, int v, int &l, int &r) {
        if (!p) l = r = 0;
        else {
          if (val[p] <= v) {
            l = p;
            split_v(rs[p], v, rs[l], r);
            pushup(l);
          }
          else {
            r = p;
            split_v(ls[p], v, l, ls[r]);
            pushup(r);
          }
        }
      }
      void insert(int &p, int x) {
        int A, B, C;
        split_v(p, x - 1, A, B);
        split_v(B, x, B, C);
        if (size[B] > 0) cnt[B]++;
        else B = newnode(x);
        p = join(join(A, B), C);
      }
      void erase(int &p, int x) {
        int A, B, C;
        split_v(p, x - 1, A, B);
        split_v(B, x, B, C);
        if (--cnt[B] == 0) B = 0;
        p = join(join(A, B), C);
      }
      int mex(int p) {
        int c = 0;
        while (p) {
          int lsize = size[ls[p]] + 1;
          if (lsize + c == val[p] + 1) {
            c += lsize;
            p = rs[p];
          }
          else {
            p = ls[p];
          }
        }
        return c;
      }
    } // namespace treap
    using namespace treap;
    int root[Maxn];
    
    void re_clear() {
      for (int i = 1; i <= n; ++i) {
        g[i].clear();
        deg[i] = 0;
      }
      memset(root, 0, (n + 1) << 2);
    }
    
    void Main() {
    
      read(&n), read(&m);
      for (int i = 1; i <= n; ++i) {
        read(a + i);
        if (a[i] > n) a[i] = n + 1;
      }
      for (int i = 1; i <= m; ++i) {
        int u, v;
        read(&u), read(&v);
        add_edge(u, v);
        add_edge(v, u);
      }
    
      static const auto cmp_node =
      [&](int x, int y)->bool {
        return deg[x] > deg[y];
      };
      for (int i = 1; i <= n; ++i)
        sort(g[i].begin(), g[i].end(), cmp_node);
      init_treap();
      for (int u = 1; u <= n; ++u)
        if (deg[u] > BL) {
          for (int &v: g[u]) treap::insert(root[u], a[v]);
        }
    
      read(&q);
      while (q--) {
        int op, u, x;
        read(&op), read(&u);
        if (op == 1) {
          read(&x);
          if (x > n) x = n + 1;
          for (int &v: g[u]) {
            if (deg[v] <= BL) break;
            treap::erase(root[v], a[u]);
            treap::insert(root[v], x);
          }
          a[u] = x;
        }
        else {
          if (deg[u] <= BL) {
            for (int &v: g[u])
              appear[a[v]] = true;
            for (int i = 0; ; ++i)
              if (!appear[i]) {
                printf("%d
    ", i);
                break;
              }
            for (int &v: g[u])
              appear[a[v]] = false;
          }
          else {
            printf("%d
    ", treap::mex(root[u]));
          }
        }
      }
    
      re_clear();
    
    }
    
    int main() {
    
      fread(_I_Buffer, 1, _I_Buffer_Size, stdin);
    
      int tests;
      read(&tests);
      while (tests--) Main();
    
      return 0;
    
    }
    
    
  • 相关阅读:
    hadoop再次集群搭建(3)-如何选择相应的hadoop版本
    48. Rotate Image
    352. Data Stream as Disjoint Interval
    163. Missing Ranges
    228. Summary Ranges
    147. Insertion Sort List
    324. Wiggle Sort II
    215. Kth Largest Element in an Array
    快速排序
    280. Wiggle Sort
  • 原文地址:https://www.cnblogs.com/libra9z/p/13396825.html
Copyright © 2011-2022 走看看