Hard
Range XOR Queries with Subarray Reversals — C++
Full explanation · Time O(n + qlogn) · Space O(n)
// Time: O(n + qlogn)
// Space: O(n)
// template from: https://cp-algorithms.com/data_structures/treap.html
using pTreapNode = struct TreapNode *;
struct TreapNode {
int prior, value, cnt;
int xor_sum; // added
bool rev;
pTreapNode l, r;
TreapNode (int v) : value(v), prior(rand()), cnt(1), xor_sum(v), rev(false), l(nullptr), r(nullptr) {} // added
};
int cnt(pTreapNode t) {
return t ? t->cnt : 0;
}
int xor_sum(pTreapNode t) { // added
return t ? t->xor_sum : 0;
}
void upd_cnt(pTreapNode t) {
if (t) {
t->cnt = cnt(t->l) + cnt(t->r) + 1;
t->xor_sum = t->value ^ xor_sum(t->l) ^ xor_sum(t->r); // added
}
}
void push(pTreapNode t) {
if (t && t->rev) {
t->rev = false;
swap(t->l, t->r);
if (t->l) t->l->rev ^= true;
if (t->r) t->r->rev ^= true;
}
}
void merge(pTreapNode& t, pTreapNode l, pTreapNode r) {
push(l);
push(r);
if (!l || !r)
t = l ? l : r;
else if (l->prior > r->prior)
merge(l->r, l->r, r), t = l;
else
merge(r->l, l, r->l), t = r;
upd_cnt(t);
}
void split(pTreapNode t, pTreapNode& l, pTreapNode& r, int key, int add = 0) {
if (!t)
return void(l = r = 0);
push(t);
int cur_key = add + cnt(t->l);
if (key <= cur_key)
split(t->l, l, t->l, key, add), r = t;
else
split(t->r, t->r, r, key, add + 1 + cnt(t->l)), l = t;
upd_cnt(t);
}
void reverse(pTreapNode t, int l, int r) {
pTreapNode t1, t2, t3;
split(t, t1, t2, l);
split(t2, t2, t3, r - l + 1);
t2->rev ^= true;
merge(t, t1, t2);
merge(t, t, t3);
}
void heapify(pTreapNode t) {
if (!t) return;
pTreapNode max = t;
if (t->l && t->l->prior > max->prior)
max = t->l;
if (t->r && t->r->prior > max->prior)
max = t->r;
if (max != t) {
swap(t->prior, max->prior);
heapify(max);
}
}
pTreapNode build(const vector<int>& a, int i, int n) {
if (n == 0) return nullptr;
int mid = n / 2;
auto t = new TreapNode(a[i + mid]);
t->l = build(a, i, mid);
t->r = build(a, i + mid + 1, n - mid - 1);
heapify(t);
upd_cnt(t);
return t;
}
// treap
class Solution {
public:
vector<int> getResults(vector<int>& nums, vector<vector<int>>& queries) {
pTreapNode root = build(nums, 0, size(nums));
const auto& update = [&](int index, int value) {
pTreapNode left, mid, right;
split(root, left, mid, index);
split(mid, mid, right, 1);
mid->value = value;
upd_cnt(mid);
merge(root, left, mid);
merge(root, root, right);
};
const auto& query = [&](int left, int right) {
pTreapNode t1, t2, t3;
split(root, t1, t2, left);
split(t2, t2, t3, right - left + 1);
int result = xor_sum(t2);
merge(root, t1, t2);
merge(root, root, t3);
return result;
};
vector<int> result;
for (const auto& q : queries) {
if (q[0] == 1) {
update(q[1], q[2]);
} else if (q[0] == 2) {
result.emplace_back(query(q[1], q[2]));
} else if (q[0] == 3) {
reverse(root, q[1], q[2]);
}
}
return result;
}
};