【洛谷P4735】最大异或和

题目大意:给定一个长度为 N 的序列,支持两个操作:在序列末尾添加一个新的数字,查询序列区间 \([l,r]\) 内使得 \(a_p\oplus a_{q+1}\oplus ... a_N\oplus x\) 值最大。

题解:由于是查询区间的最大异或值,可知应该使用可持久化数据结构,再由于是最大异或和,可知采用可持久化 Trie + 前缀和处理。在 Trie 的每个节点上维护一个 size,表示该节点是多少个数字的二进制前缀,查询过程类似于主席树。

代码如下

#include <bits/stdc++.h>

using namespace std;

const int maxn = 6e5 + 10;

struct node {
	node *l, *r;
	int sz;
	void pull() {
		this->sz = 0;
		if (l != NULL) {
			this->sz += l->sz;
		}
		if (r != NULL) {
			this->sz += r->sz;
		}
	}
} pool[maxn * 24];
node *newnode() {
	static int cnt = 0;
	return &pool[cnt++];
}
node *insert(node *pre, int bit, int val) {
	node *cur = newnode();
	if (pre) {
		*cur = *pre;
	}
	if (bit < 0) {
		cur->sz++;
		return cur;
	}
	if (val >> bit & 1) {
		cur->r = insert(pre ? pre->r : NULL, bit - 1, val);
	} else {
		cur->l = insert(pre ? pre->l : NULL, bit - 1, val);
	}
	cur->pull();
	return cur;
}
int query(node *cur, node *pre, int bit, int val) {
	if (bit < 0) {
		return 0;
	}
	int now = val >> bit & 1;
	if (now == 0) {
		int rsz = 0;
		if (cur && cur->r) rsz += cur->r->sz;
		if (pre && pre->r) rsz -= pre->r->sz;
		if (rsz > 0) {
			return (1 << bit) + query(cur ? cur->r : NULL, pre ? pre->r : NULL, bit - 1, val);
		} else {
			return query(cur ? cur->l : NULL, pre ? pre->l : NULL, bit - 1, val);
		}
	} else {
		int lsz = 0;
		if (cur && cur->l) lsz += cur->l->sz;
		if (pre && pre->l) lsz -= pre->l->sz;
		if (lsz > 0) {
			return (1 << bit) + query(cur ? cur->l : NULL, pre ? pre->l : NULL, bit - 1, val);
		} else {
			return query(cur ? cur->r : NULL, pre ? pre->r : NULL, bit - 1, val);
		}
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	vector<int> sum(n + 1);
	vector<node*> rt(n + 1);
	rt[0] = insert(NULL, 25, 0);
	for (int i = 1, x; i <= n; i++) {
		cin >> x;
		sum[i] = sum[i - 1] ^ x;
		rt[i] = insert(rt[i - 1], 25, sum[i]);
	}
	while (m--) {
		string opt;
		cin >> opt;
		if (opt[0] == 'A') {
			int x;
			cin >> x;
			int val = sum.back() ^ x;
			sum.push_back(val);
			node *cur = insert(rt.back(), 25, val);
			rt.push_back(cur);
		} else {
			int l, r, x;
			cin >> l >> r >> x;
			l--, r--;
			if (l == 0) {
				cout << query(rt[r], NULL, 25, x ^ sum.back()) << endl;
			} else {
				cout << query(rt[r], rt[l - 1], 25, x ^ sum.back()) << endl;
			}
		}
	}
	return 0;
}
posted @ 2019-02-20 12:37  shellpicker  阅读(310)  评论(0编辑  收藏  举报