Description
比特集合是一种抽象数据类型(Abstract Data Type) ,其包含一个集合S,并支持如下几种操作:
INS M : 将元素 M 插入到集合S中;
DEL M : 将集合S中所有等于 M 的元素删除;
ADD M : 将集合S中的所有元素都增加数值M ;
QBIT k : 查询集合中有多少个元素满足其二进制的第 k位为 1 。
初始时,集合S为空集。请实现一个比特集合,并对于所有的QBIT操作输出相应的答案。
INS M : 将元素 M 插入到集合S中;
DEL M : 将集合S中所有等于 M 的元素删除;
ADD M : 将集合S中的所有元素都增加数值M ;
QBIT k : 查询集合中有多少个元素满足其二进制的第 k位为 1 。
初始时,集合S为空集。请实现一个比特集合,并对于所有的QBIT操作输出相应的答案。
Input
输入第一行包含一个正整数N,表示操作的数目。
接下来N行,每行为一个操作,格式见问题描述。
接下来N行,每行为一个操作,格式见问题描述。
Output
对于每一个QBIT操作,输出一行,表示相应的答案。
Sample Input
8
INS 1
QBIT 0
ADD 1
QBIT 0
QBIT 1
DEL 2
INS 1
QBIT 1
INS 1
QBIT 0
ADD 1
QBIT 0
QBIT 1
DEL 2
INS 1
QBIT 1
Sample Output
1
0
1
0
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; }