[NOI2017 D1T1]整数

题目大意:有一个整数 $x$ ,一开始为 $0$ 。有 $n$ 个操作,有两种类型:

$1 \;a\; b$:将 $x$ 加上整数 $a\cdot 2^b$ ,其中 $a$ 为一个整数, $b$ 为一个非负整数

$2\; k$ :询问 $x$ 在用二进制表示时,第 $2^k$ 位的值($0$或$1$)

保证在任何时候, $x\geq 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\n", k);
			printf("%d\n", query(k));
//			puts("query");
		} else {
			int a, b;
			scanf("%d%d", &a, &b);
			if (!a) continue;
			modify(a, b);
//			puts("modify");
		}
	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/9463961.html