B2568 比特集合 树状数组
啊啊啊,跳题坑死人。抽了一道国集的题,自己瞎编了一个算法,好像过不了而半途而废。转去看题解,发现用二维树状数组维护一下,偏移量我倒是想对了,但是维护的东西和我的完全不一样。还是有很大差距啊。。。
吐槽一个事,谁能给我讲讲位运算的优先级?
#include<iostream> #include<cstring> #include<ctime> #include<cmath> #include<algorithm> #include<iomanip> #include<cstdlib> #include<cstdio> #include<map> #include<bitset> #include<set> #include<stack> #include<vector> #include<queue> using namespace std; #define MAXN 1010 #define MAXM 1010 #define ll long long #define eps 1e-8 #define MOD 1000000007 #define INF 1000000000 #define lb(x) x & -x int m; int N=1<<16; char o[MAXN]; int c[17][1000010]; int ch; map<int,int>h; void change(int *c,int x,int y) { for(; x <= N; x += lb(x)) { c[x] += y; } } int ask(int *c,int x) { int re=0; for(; x; x -= lb(x)) { re += c[x]; } return re; } int main() { int i; int x; scanf("%d",&m); while(m--) { scanf("%s",o); if(o[0] == 'I') { scanf("%d",&x); h[x - ch]++; //ch为偏移量 for(i = 1; i <= 16;i++) { change(c[i],(x - ch & ((1 << i) - 1)) + 1,1);//维护树状数组 } } if(o[0] == 'D') { scanf("%d",&x); for(i = 1; i <= 16; i++) { change(c[i],(x - ch & ((1 << i) - 1)) + 1,-h[x - ch]);//正常的删除操作 } h[x - ch] = 0; } if(o[0] == 'A') { scanf("%d",&x); ch += x; } if(o[0] == 'Q') { scanf("%d",&x); int ans = 0; ans += ask(c[x + 1],min(max((1 << x + 1) - (ch & ((1 << x + 1) - 1)),0),1 << x + 1)); ans -= ask(c[x + 1],min(max((1 << x) - (ch & ((1 << x + 1) - 1)),0),1 << x + 1)); //这里最不好理解,前两句是统计没有进位的情况 //下两句统计进位的情况,有点复杂 //这块理解不了可以去链接看一眼 (其实我也不太懂) ans += ask(c[x + 1],min(max((1 << x + 2)-(ch & ((1 << x + 1) - 1)),0),1 << x + 1)); ans -= ask(c[x + 1],min(max((1 << x) + (1 << x + 1)-(ch & ((1 << x + 1) - 1)),0),1 << x + 1)); printf("%d\n",ans); } } return 0; } /* 8 INS 1 QBIT 0 ADD 1 QBIT 0 QBIT 1 DEL 2 INS 1 QBIT 1 */
题干:
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可以包含多个重复元素。 Source 2012国家集训队Round 1 day4
我的凉凉代码(都没写完):
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> #include<map> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } priority_queue <int> qu; int cha[20],a[500005]; int tot[20],n,x,q = 0; int k[20]; char s[10]; void ins(int x) { int len = 0,ok = 0; clean(k); while(x != 0) { if(x % 2 == 1) { tot[len]++; k[len] = 1; if(k[len - 1] == 1) cha[len]++; } x /= 2; len++; } } void add(int x) { q += x; } int main() { read(n); duke(i,1,n) { scanf("%s",s); if(s[0] == 'I') { read(x); ins(x); qu.push(x - q); } else if(s[0] == 'A') { read(x); add(x); } else if(s[0] == 'D') { read(x); del(x); } else { read(x); qbit(x); } } }
正解(不是我写的,但是我改了一下,加了点注释)
只想找一个不会伤害我的人