【题目背景】
在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科
学家 P 博士正用它进行各种研究。不幸的是,这天台风切断了电力系统,超级计算机
无法工作,而 P 博士明天就要交实验结果了,只好求助于学过 OI 的你. . . . . .
【题目描述】
P 博士将他的计算任务抽象为对一个整数的操作。
具体来说,有一个整数 x ,一开始为 0。
接下来有 n 个操作,每个操作都是以下两种类型中的一种:
1 a b :将 x 加上整数 a · 2
b,其中 a 为一个整数,b 为一个非负整数
2 k :询问 x 在用二进制表示时,位权为 2
k 的位的值(即这一位上的 1 代表 2
k )
保证在任何时候,x ≥ 0。
【输入格式】
从文件 integer.in 中读入数据。
输入的第一行包含四个正整数 n, t1, t2, t3,n 的含义见题目描述,t1, t2, t3 的具体含义
见子任务。
接下来 n 行,每行给出一个操作,具体格式和含义见题目描述。
同一行输入的相邻两个元素之间,用恰好一个空格隔开。
【输出格式】
输出到文件 integer.out 中。
对于每个询问操作,输出一行,表示该询问的答案(0 或 1)。对于加法操作,没有
任何输出。
【样例 1 输入】
10 3 1 2
1 100 0
1 2333 0
1 -233 0
2 5
2 7
2 15
1 5 15
2 15
1 -1 12
2 15
【样例 1 输出】
0
1
0
1
0
【样例 1 解释】
样例中有 10 个操作:第 1 个为将 x 加上 100 × 2
0 ,操作后,x = 100 ;
第 2 个为将 x 加上 2333 × 2
0 ,操作后,x = 2433 ;
第 3 个为将 x 加上 ?233 × 2
0 ,操作后,x = 2200 ;
第 4 个为询问 x 位权为 2
5 的位上的值,x 在二进制下为 100010011000 ,答案为 0 ;
第 5 个为询问 x 位权为 2
7 的位上的值,x 在二进制下为 100010011000 ,答案为 1 ;
第 6 个为询问 x 位权为 2
15 的位上的值,x 在二进制下为 100010011000 ,答案为
0 ;
第 7 个为将 x 加上 5 × 2
15 = 163840 ,操作后,x = 166040 ;
第 8 个为询问 x 位权为 2
15 的位上的值,x 在二进制下为 101000100010011000 ,答
案为 1 ;
第 9 个为将 x 加上 ?1 × 2
12 = ?4096 ,操作后,x = 161944 ;
第 10 个为询问 x 位权为 2
15 的位上的值,x 在二进制下为 100111100010011000 ,
答案为 0 。
首先把a*b拆分成log次单加操作。然后考虑对于一个位上的单加操作。如果不进位可以直接加,进位实际上是找到一串连续的1后的第一个0,并且把这一串1都变成0,将最后一个0变成1。可以用线段树优化。在线段树上维护两个bits信息,一个是否全0,一个是否全1。注意到这两个信息可以用位运算向上更新。复杂度O(n log^2 n)但是这样做对于100%的数据是会TLE的。发现线段树每一个节点只有0或1太浪费了。考虑状态压缩01串到一个32位整型中。这样复杂度是O(n log^2 n / 32),可以过了。
P.S.洛谷上被卡常了555……
#include<cstdio> #include<cctype> using namespace std; const int block = 30; const int maxn = 1e6 + 150, stmax = (1LL << block) - 1; int n, a, b, N, opt, t1, t2, t3, f = 0; inline char gc(){ static char buf[2000000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 2000000, stdin), p1 == p2) ? EOF : *p1++; } inline void read(int & x) { x = 0, f = 0;static char c = gc(); while(!isdigit(c)) { if(c == '-') f = 1; c = gc(); } while(isdigit(c)) x = x * 10 + c - '0', c = gc(); if(f) x = -x; } namespace Segtree { struct node {int bits[2], edt;node() {edt = -1;}}tree[maxn << 2]; void push_up(int rt) { tree[rt].bits[0] = tree[rt << 1].bits[0] | tree[rt << 1 | 1].bits[0]; tree[rt].bits[1] = tree[rt << 1].bits[1] & tree[rt << 1 | 1].bits[1]; } void push_down(int rt) { if(~tree[rt].edt) { tree[rt << 1].edt = tree[rt << 1].bits[0] = tree[rt << 1].bits[1] = tree[rt].edt; tree[rt << 1 | 1].edt = tree[rt << 1 | 1].bits[0] = tree[rt << 1 | 1].bits[1] = tree[rt].edt; tree[rt].edt = -1; } } int qNful(int p, int tl, int tr, int rt, int t, int des) { if(tree[rt].bits[t] == des) return -1; if(tl == tr) return tl; push_down(rt); int mid = tl + tr >> 1; if(p < mid) { int ret = qNful(p, tl, mid, rt << 1, t, des); return (~ret) ? ret : qNful(p, mid + 1, tr, rt << 1 | 1, t, des); } return qNful(p, mid + 1, tr, rt << 1 | 1, t, des); } void edit(int l, int r, int tl, int tr, int rt, int msk) { if(tl == l && tr == r) { tree[rt].edt = tree[rt].bits[0] = tree[rt].bits[1] = msk; return ; } push_down(rt); int mid = tl + tr >> 1; if(r <= mid) edit(l, r, tl, mid, rt << 1, msk); else if(l > mid) edit(l, r, mid + 1, tr, rt << 1 | 1, msk); else { edit(l, mid, tl, mid, rt << 1, msk); edit(mid + 1, r, mid + 1, tr, rt << 1 | 1, msk); } push_up(rt); } void add(int p, int tl, int tr, int rt, int dt) { if(tl == tr) { tree[rt].bits[0] = (tree[rt].bits[1] += dt); return ; } push_down(rt); int mid = tl + tr >> 1; if(p <= mid) add(p, tl, mid, rt << 1, dt); else add(p, mid + 1, tr, rt << 1 | 1, dt); push_up(rt); } int query(int p, int tl, int tr, int rt) { if(tl == tr) return tree[rt].bits[0]; push_down(rt); int mid = tl + tr >> 1; if(p <= mid) return query(p, tl, mid, rt << 1); else return query(p, mid + 1, tr, rt << 1 | 1); } void plus(int p, int msk) { int now = query(p, 0, N, 1); if(now + msk <= stmax) add(p, 0, N, 1, msk); else { add(p, 0, N, 1, -(stmax - msk + 1)); // 减去前面的连续1 now = qNful(p, 0, N, 1, 1, stmax); if(p + 1 < now)edit(p + 1, now - 1, 0, N, 1, 0); add(now, 0, N, 1, 1); } } void minus(int p, int msk) { int now = query(p, 0, N, 1); if(now - msk >= 0) add(p, 0, N, 1, -msk); else { add(p, 0, N, 1, (stmax - msk + 1)); // 加上前面的连续1 now = qNful(p, 0, N, 1, 0, 0); if(p + 1 < now)edit(p + 1, now - 1, 0, N, 1, stmax); add(now, 0, N, 1, -1); } } } inline void opr(int a, int b) { using namespace Segtree; if(!a) return ; int type = a > 0, pw = 0; if(!type) a = -a; while(a) { if(a & 1) if(type) plus((pw + b) / block, 1 << ((pw + b) % block)); else minus((pw + b) / block, 1 << ((pw + b) % block)); a >>= 1, ++pw; } } int main() { using namespace Segtree; scanf("%d%d%d%d", &n, &t1, &t2, &t3), N = 1e6 + 100; while(n--) { read(opt), read(a); if(opt == 1) { read(b); opr(a, b); } else { putchar((query(a / block, 0, N, 1) & (1 << (a % block))) ? '1' : '0'); putchar('\n'); } } return 0; }
没有帐号? 立即注册