• BZOJ2568 [国家集训队2012]比特集合


    Description

      比特集合是一种抽象数据类型(Abstract Data Type) ,其包含一个集合S,并支持如下几种操作:
      INS M : 将元素 M 插入到集合S中;
      DEL M : 将集合S中所有等于 M 的元素删除;
      ADD M : 将集合S中的所有元素都增加数值M
      QBIT k : 查询集合中有多少个元素满足其二进制的第 k位为 1
      初始时,集合S为空集。请实现一个比特集合,并对于所有的QBIT操作输出相应的答案。

    Input

      输入第一行包含一个正整数N,表示操作的数目。
      接下来N行,每行为一个操作,格式见问题描述。

    Output

      对于每一个QBIT操作,输出一行,表示相应的答案。

    Sample Input

    8
    INS 1
    QBIT 0
    ADD 1
    QBIT 0
    QBIT 1
    DEL 2
    INS 1
    QBIT 1

    Sample Output

    1
    0
    1
    0

    HINT

    数据规模和约定

      时间限制2s。

      对于30%的数据,1 ≤ N ≤ 10000。

      对于100%的数据,1 ≤ N ≤ 500000;QBIT操作中的k满足, 0 ≤ k < 16。INS/DEL操作中,满足0 ≤ M ≤ 10^9;ADD操作中, 满足0 ≤ M ≤ 1000。

    注意

      注意集合S可以包含多个重复元素。

    题解

    首先我们可以发现整体加只是要维护一个标记cnt表示当前加了多少,那么add x->add (x - cnt), del x -> del (x - cnt), qbit k ->查询加cnt之后第k位为1的数的个数<=>查询后k位在$[2^k - cnt, 2^{k + 1} - 1 - cnt]$范围内的数。

    令$c[i][j]$表示后$i$位小于等于$j$的数的个数,用树状数组维护,那么答案就是$num - c[i][2^k-1]$(没有计$cnt$的影响)。

    附代码:

    #include <algorithm>
    #include <cstdio>
    #include <set>
    typedef long long LL;
    const int mod = 1000000009;
    inline int lowbit(int x) { return x & -x; }
    const int N = 1 << 16;
    int s[16][N];
    void add(int a, int k, int x) {
      for (++k; k <= N; k += lowbit(k))
        s[a][k] += x;
    }
    int query(int a, int k) {
      int ans = 0;
      for (++k; k; k -= lowbit(k)) ans += s[a][k];
      return ans;
    }
    std::multiset<int> S;
    int main() {
      int m, x, cnt = 0, num = 0;
      scanf("%d", &m);
      char s[10];
      while (m--) {
        scanf("%s%d", s, &x);
        if (*s == 'I') {
          ++num;
          S.insert(x -= cnt);
          for (int i = 0; i < 16; ++i) add(i, ((1 << (i + 1)) - 1) & x, 1);
        } else if (*s == 'D') {
          int l = S.count(x -= cnt);
          num -= l;
          S.erase(x);
          for (int i = 0; i < 16; ++i) add(i, ((1 << (i + 1)) - 1) & x, -l);
        } else if (*s == 'A') {
          cnt += x;
        } else {
          int r = ((1 << x) - cnt - 1) & ((1 << (x + 1)) - 1), l = (-cnt) & ((1 << (x + 1)) - 1);
          if (r >= l)
            printf("%d
    ", num - query(x, r) + query(x, l - 1));
          else
            printf("%d
    ", query(x, l - 1) - query(x, r));
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    JS中Text节点总结
    JS中Document节点总结
    HTML5 Geolocation位置信息定位总结
    HTML5form表单的相关知识总结
    HTML5文档的各个组成部分分类
    JS中Node节点总结
    vue.js指令总结
    javascript string对象方法总结
    php 接口文档自动生产方式
    python使用
  • 原文地址:https://www.cnblogs.com/y-clever/p/7326026.html
Copyright © 2020-2023  润新知