NAOJ33 bst

题目蓝链

Solution

这道题我一开始打挂了,因为我没有考虑反转会对修改也产生影响。我们可以考虑建立一颗线段树来维护,对于每一个点开一个标记,标记的每一个二进制为表示在当前子树的第几层会全部翻转。我们只需要在修改和查询的时候把这个标记\(push\_down\)一下就可以了

另外注意在修改操作的时候,因为行与行之间会产生冲突,所以只能一行一行的修改。但中间的行都是完整的,所以度杂度是\(\mathcal{O}(1)\)。只有两端的位置也就是两行需要在线段上去修改,复杂度为\(\mathcal{O}(\log n)\)

另外注意,在修改和查询的时候。在每一个点都要看一下在当前层有没有需要反转的标记,有就更改一下方向

Code

#include <bits/stdc++.h>

using namespace std;

#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

inline int read() {
	int sum = 0, fg = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
	return fg * sum;
}

const int maxn = 1e6 + 10;

int N, n, q, Pow[21];

namespace ST {

	int A[maxn << 4], tag[maxn << 4];
#define ls (rt << 1)
#define rs (rt << 1 | 1)

	void push_down(int rt) {
		if (!tag[rt]) return;
		tag[ls] ^= tag[rt], tag[rs] ^= tag[rt];
		A[ls] ^= tag[rt], A[rs] ^= tag[rt];
		tag[rt] = 0;
	}

	void change(int rt, int l, int r, int L, int R, int dep, int p) {
		if (L <= l && r <= R) { A[rt] ^= Pow[p], tag[rt] ^= Pow[p]; return; }
		push_down(rt);
		int mid = (l + r) >> 1, tt = (A[rt] & Pow[dep]) ? 1 : 0;
		if (L <= mid) change(ls ^ tt, l, mid, L, R, dep + 1, p);
		if (R > mid) change(rs ^ tt, mid + 1, r, L, R, dep + 1, p);
	}

	int query(int rt, int l, int r, int x, int dep) {
		if (l == r) return rt - (Pow[n] - 1);
		push_down(rt);
		int mid = (l + r) >> 1, tt = (A[rt] & Pow[dep]) ? 1 : 0;
		if (x <= mid) return query(ls ^ tt, l, mid, x, dep + 1);
		else return query(rs ^ tt, mid + 1, r, x, dep + 1);
	}

}

int main() {
#ifdef xunzhen
	freopen("33.in", "r", stdin);
	freopen("33.out", "w", stdout);
#endif

	n = read(); q = read(); N = 1 << n;
	Pow[0] = 1; for (int i = 1; i <= 20; i++) Pow[i] = Pow[i - 1] << 1;
	while (q--) {
		int op = read();
		if (op == 1) {
			int l = read(), r = read();
			for (int i = 0; i < n; i++)
				if (l < Pow[i + 1] && r >= Pow[i]) {
					int x = max(l, Pow[i]), y = min(r, Pow[i + 1] - 1);
					if (x == Pow[i] && y == (Pow[i + 1] - 1)) ST::A[1] ^= Pow[i], ST::tag[1] ^= Pow[i];
					else ST::change(1, 1, Pow[i], x - (Pow[i] - 1), y - (Pow[i] - 1), 0, i);
				}
		}else {
			int x = read();
			printf("%d\n", ST::query(1, 1, N, x, 0));
		}
	}

	return 0;
}

Summary

这道题要做出来,需要非常灵活地使用线段树

做之前要仔细考虑翻转会产生的影响

posted @ 2018-09-29 14:51  xunzhen  阅读(195)  评论(0编辑  收藏  举报