Description
P 博士将他的计算任务抽象为对一个整数的操作。
具体来说,有一个整数 (x) ,一开始为 (0) 。
接下来有 (n) 个操作,每个操作都是以下两种类型中的一种:
1 a b
:将 (x) 加上整数 (acdot 2^b) ,其中 (a) 为一个整数, (b) 为一个非负整数2 k
:询问 (x) 在用二进制表示时,位权为 (2^k) 的位的值(即这一位上的 (1) 代表 (2^k) )
保证在任何时候, (xgeqslant 0) 。
(1leq nleq 10^6,|a| leq 10^9,0 leq b, k leq 30n)
Solution
考虑稍微暴力一点的做法,我们开两个数组来模拟进位(一个是 (a > 0) ,另一个 (a < 0) )。
然后对于询问,我们假设小于 (k) 位的部分 (a>0) 的是 (s_1) , (a<0) 的是 (s_2) 。
讨论所有情况,我们可以得出结论:
- 若 (s_1geq s2) ,输出答案为 ([xoplus y]) ,其中 (x) 是 (a>0) 的第 (k) 位的值, (y) 是 (a<0) 的第 (k) 位的值。
- 若 (s_1< s2) ,输出答案为 ([x=y]) 。
这样总复杂度是 (O(30nlog(30n))) 的。
考虑优化。
直接拿 ( ext{zkw线段树}) 卡过去啦!
Code
#include <bits/stdc++.h>
using namespace std;
const int M = 1000000*30+300;
void gi(int &x) {
char ch = getchar(); x = 0; int flag = 0;
for (; ch < '0' || ch > '9'; ch = getchar()) flag |= (ch == '-');
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x<<1)+(x<<3)+ch-48;
if (flag) x = -x;
}
int s1[M], s2[M], tr[(1<<26)+5];
int n, N, rbsc, opt, a, b, lst[32], bin[32], tot;
void modify(int *s, int a, int b) {
tot = 0;
for (int i = 30; i >= 0 && a; i--)
if (bin[i]&a) lst[++tot] = i, a -= bin[i];
int r = lst[1]+b, l = lst[tot]+b;
for (int i = 1; i <= tot; i++) {
int loc = lst[i]+b;
while (s[loc]) s[loc++] = 0;
r = max(r, loc), s[loc] = 1;
}
for (int i = l; i <= r; i++) tr[N+i] = (s1[i]^s2[i]);
for (l = (l+N)>>1, r = (r+N)>>1; l; l >>= 1, r >>= 1)
for (int j = l; j <= r; j++) tr[j] = tr[j<<1]|tr[j<<1|1];
}
int query(int a) {
for (a += N; a; a >>= 1)
if (a&1&tr[a^1]) {
for (a ^= 1; a < N; a = a<<1|tr[a<<1|1]);
return a-N;
}
return -1;
}
void work() {
gi(n); gi(rbsc), gi(rbsc), gi(rbsc);
for (N = 1; N <= n*30; N <<= 1);
bin[0] = 1; for (int i = 1; i <= 30; i++) bin[i] = (bin[i-1]<<1);
while (n--) {
gi(opt);
if (opt == 1) {
gi(a), gi(b);
if (a < 0) modify(s2, -a, b);
else modify(s1, a, b);
}else {
gi(a); int now = query(a);
if (now == -1 || s1[now] > s2[now]) putchar('0'+(s1[a]^s2[a]));
else putchar('0'+(s1[a] == s2[a]));
putchar('
');
}
}
}
int main() {work(); return 0; }