题目大意:有一个整数 $x$ ,一开始为 $0$ 。有 $n$ 个操作,有两种类型:
$1 ;a; b$:将 $x$ 加上整数 $acdot 2^b$ ,其中 $a$ 为一个整数, $b$ 为一个非负整数
$2; k$ :询问 $x$ 在用二进制表示时,第 $2^k$ 位的值($0$或$1$)
保证在任何时候, $xgeq 0$ 。
题解:压位线段树,每一个节点压$30$位,考虑到有加减操作,而对于加操作,只是把这一位前的第一个$0$变成$1$,把其间的$1$变成$0$,减相反。所以我们可以在线段树中存一下区间$AND$和区间$OR$,找到某一位前的第一个$1$或第一个$0$,线段树修改一下就行了
卡点:线段树中的$update$和$pushdown$中把$rc$写成了$rt$($QAQ$)
C++ Code:
#include <cstdio> #include <cstring> #define base 30 #define maxn 1000010 using namespace std; const int inf = (1 << base) - 1; int n, op; struct ST { int And[maxn << 2], Or[maxn << 2], V[maxn << 2], tg[maxn << 2]; void init() { memset(tg, -1, sizeof tg); } void pushdown(int rt) { int lc = rt << 1, rc = rt << 1 | 1, &tmp = tg[rt]; And[lc] = Or[lc] = tg[lc] = tmp; And[rc] = Or[rc] = tg[rc] = tmp; tmp = -1; } void update(int rt) { int lc = rt << 1, rc = rt << 1 | 1; And[rt] = And[lc] & And[rc]; Or[rt] = Or[lc] | Or[rc]; } void add(int rt, int l, int r, int p, int num) { if (l > r) return ; if (l == r) { Or[rt] = And[rt] = num; return ; } int mid = l + r >> 1; if (~tg[rt]) pushdown(rt); if (p <= mid) add(rt << 1, l, mid, p, num); else add(rt << 1 | 1, mid + 1, r, p, num); update(rt); } void add(int rt, int l, int r, int L, int R, int num) { if (l > r || L > R) return ; if (L <= l && R >= r) { Or[rt] = And[rt] = tg[rt] = num; return ; } int mid = l + r >> 1; if (~tg[rt]) pushdown(rt); if (L <= mid) add(rt << 1, l, mid, L, R, num); if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, num); update(rt); } int ask(int rt, int l, int r, int p) { if (l > r) return 0; if (l == r) return And[rt]; int mid = l + r >> 1, ans; if (~tg[rt]) pushdown(rt); if (p <= mid) ans = ask(rt << 1, l, mid, p); else ans = ask(rt << 1 | 1, mid + 1, r, p); return ans; } int find_1(int rt, int l, int r, int p) { if (Or[rt] == 0) return -1; if (l == r) return l; int mid = l + r >> 1; if (~tg[rt]) pushdown(rt); if (p <= mid) { int tmp = find_1(rt << 1, l, mid, p); return ~tmp ? tmp : find_1(rt << 1 | 1, mid + 1, r, p); } else return find_1(rt << 1 | 1, mid + 1, r, p); } int find_0(int rt, int l, int r, int p) { if (And[rt] == inf) return -1; if (l == r) return l; int mid = l + r >> 1; if (~tg[rt]) pushdown(rt); if (p <= mid) { int tmp = find_0(rt << 1, l, mid, p); return ~tmp ? tmp : find_0(rt << 1 | 1, mid + 1, r, p); } else return find_0(rt << 1 | 1, mid + 1, r, p); } } T; void inc(int p, int num) { if (!num) return ; int tmp = T.ask(1, 0, maxn, p) + num; if (tmp <= inf) T.add(1, 0, maxn, p, tmp); else { T.add(1, 0, maxn, p, tmp & inf); int pos = T.find_0(1, 0, maxn, p + 1); T.add(1, 0, maxn, p + 1, pos - 1, 0); inc(pos, 1); } } void dec(int p, int num) { if (!num) return ; int tmp = T.ask(1, 0, maxn, p) - num; if (tmp >= 0) T.add(1, 0, maxn, p, tmp); else { T.add(1, 0, maxn, p, tmp + inf + 1); int pos = T.find_1(1, 0, maxn, p + 1); T.add(1, 0, maxn, p + 1, pos - 1, inf); dec(pos, 1); } } void modify(int a, int b) { int blo = b / base, num = b % base; if (a > 0) { inc(blo, (a << num) & inf); a = a >> base - num; if (a) inc(blo + 1, a); } else { a = -a; dec(blo, (a << num) & inf); a = a >> base - num; if (a) dec(blo + 1, a); } } int query(int k) { int tmp = T.ask(1, 0, maxn, k / base); return (tmp & (1 << k % base)) && 1; } int main() { // freopen("integer.in", "r", stdin); // freopen("integer.out" ,"w", stdout); scanf("%d%*d%*d%*d", &n); T.init(); while (n--) { scanf("%d", &op); if (op --> 1) { int k; scanf("%d", &k); // printf("%d ", k); printf("%d ", query(k)); // puts("query"); } else { int a, b; scanf("%d%d", &a, &b); if (!a) continue; modify(a, b); // puts("modify"); } } return 0; }