In this HackerEarth XOR in Tree problem In Graph theory, tree is a simple connected acyclic graph. You are given a tree consists of N nodes numbered from 1 to N. Each node i have a value Ai associated with it. Your task is writing a program doing Q operations, each operations is 1 of 2 following types:
  1. u, v: Assign Au to v.
  2. u, v: Calculate XOR sum of all value associated with nodes in unique single path from u to v.


HackerEarth XOR in Tree problem solution


HackerEarth XOR in Tree problem solution.

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 100000 + 10;
const int MAXL = 22;

vector<int> adj[MAXN];
int a[MAXN], subtree[MAXN], pos[MAXN], path_xor[MAXN], depth[MAXN];
int par[MAXN][MAXL];
bool visited[MAXN];
int n, m, l;

void DFS(int u) {
visited[u] = true;
subtree[u] = 1;
for(int i = 0; i < adj[u].size(); i++) {
int v = adj[u][i];
if (!visited[v]) {
path_xor[v] = path_xor[u] ^ a[v]; depth[v] = depth[u] + 1;
DFS(v);
subtree[u] += subtree[v]; par[v][0] = u;
}
}
pos[u] = m; m--;
}

void init() {
scanf("%d\n", &n);
assert((1 <= n) && (n <= 100000));
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
assert((1 <= a[i]) && (a[i] <= (int)(1e9)));
adj[i].clear();
}
for(int i = 1; i <= n - 1; i++) {
int u, v;
scanf("%d %d\n", &u, &v);
assert((1 <= u) && (u <= n));
assert((1 <= v) && (v <= n));
adj[u].push_back(v); adj[v].push_back(u);
}
for(int i = 1; i <= n; i++) visited[i] = false;
m = n;
path_xor[1] = a[1]; depth[1] = 0;
DFS(1);
l = (int)(log(n) / log(2)) + 1;
for(int j = 1; j <= l; j++) {
for(int i = 1; i <= n; i++) par[i][j] = par[par[i][j - 1]][j - 1];
}
}

struct segment_tree {
int T[8 * MAXN];
int n;

void init(int _n) {
n = _n;
for(int i = 0; i <= 8 * n; i++) T[i] = 0;
}

void lazy_propagation(int node, int from, int to) {
if (from < to) {
T[node * 2] ^= T[node]; T[node * 2 + 1] ^= T[node];
T[node] = 0;
}
}

void update(int node, int from, int to, int l, int r, int val) {
lazy_propagation(node, from, to);
if ((from > r) || (to < l)) return;
if ((from >= l) && (to <= r)) {
T[node] ^= val;
return;
}
int mid = (from + to) / 2;
update(node * 2, from, mid, l, r, val);
update(node * 2 + 1, mid + 1, to, l, r, val);
}

void get_val(int node, int from, int to, int pos, int &result) {
lazy_propagation(node, from, to);
if ((from > pos) || (to < pos)) return;
if (from == to) {
result = T[node];
return;
}
int mid = (from + to) / 2;
get_val(node * 2, from, mid, pos, result);
get_val(node * 2 + 1, mid + 1, to, pos, result);
}

void xor_range(int l, int r, int val) {
update(1, 1, n, l, r, val);
}

int get_xor(int x) {
int res = 0;
get_val(1, 1, n, x, res);
return res;
}

} ST;

void jump(int &u, int height) {
for(int i = l; i >= 0; i--) {
if (height >= (1 << i)) {
u = par[u][i];
height -= (1 << i);
}
}
}

int lca(int u, int v) {
if (depth[u] > depth[v]) jump(u, depth[u] - depth[v]); else jump(v, depth[v] - depth[u]);
if (u == v) return(u);
for(int i = l; i >= 0; i--) {
if (par[u][i] != par[v][i]) {
u = par[u][i]; v = par[v][i];
}
}
return par[u][0];
}

int main()
{
int test_cases;
cin >> test_cases;
while (test_cases --) {
init();
int q;
scanf("%d\n", &q);
assert((1 <= q) && (q <= 100000));
ST.init(n);
for(int i = 1; i <= q; i++) {
int t, u, v;
scanf("%d %d %d\n", &t, &u, &v);
assert((1 <= t) && (t <= 2));
assert((1 <= u) && (u <= n));
if (t == 1) {
assert((1 <= v) && (v <= (int)(1e9)));
ST.xor_range(pos[u], pos[u] + subtree[u] - 1, a[u] ^ v);
a[u] = v;
}
else {
assert((1 <= v) && (v <= n));
int c = lca(u, v);
int res = path_xor[u] ^ path_xor[v] ^ ST.get_xor(pos[u]) ^ ST.get_xor(pos[v]) ^ a[c];
printf("%d\n", res);
}
}
}
}

Second solution

#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cctype>
#include <cassert>
#include <limits>
#include <functional>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#if defined(_MSC_VER) || __cplusplus > 199711L
#define aut(r,v) auto r = (v)
#else
#define aut(r,v) __typeof(v) r = (v)
#endif
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define all(o) (o).begin(), (o).end()
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define mset(m,v) memset(m,v,sizeof(m))
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
using namespace std;
typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii; typedef long long ll;
template<typename T, typename U> inline void amin(T &x, U y) { if(y < x) x = y; }
template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; }

struct To {
typedef int Vertex;
Vertex to;
To() { }
To(Vertex to_): to(to_) { }
};

template<typename To_>
struct StaticGraph {
typedef To_ To;
typedef typename To::Vertex Vertex;
typedef std::pair<Vertex,To> Edge;
typedef const To *const_iterator;

void init(int n_, const std::vector<Edge> &edges) {
n = n_; int m = edges.size();
tos.resize(m+1); offsets.resize(n+1);
for(int e = 0; e < m; e ++) offsets[edges[e].first] ++;
for(int v = 1; v <= n_; v ++) offsets[v] += offsets[v-1];
for(int e = 0; e < m; e ++)
tos[-- offsets[edges[e].first]] = edges[e].second;
}
int numVertices() const { return n; }
int numEdges() const { return tos.size() - 1; }

inline const_iterator edgesBegin(int v) const { return &tos[offsets[v]]; }
inline const_iterator edgesEnd(int v) const { return &tos[offsets[v+1]]; }
private:
int n;
std::vector<To> tos;
std::vector<int> offsets;
};


class SchieberVishkinLCA {
public:
typedef StaticGraph<To> Graph;
typedef unsigned Word;
typedef Graph::Vertex Vertex;
private:

static inline Word lowestOneBit(Word v) {
return v & (~v+1);
}
static inline Word highestOneBitMask(Word v) {
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v >> 1;
}

std::vector<Word> indices;
std::vector<Word> maxHIndices;
std::vector<Word> ancestorHeights;
std::vector<Vertex> pathParents;
public:
void build(const Graph &g, Vertex root) {
return build(g, std::vector<Vertex>(1, root));
}
void build(const Graph &g, const std::vector<Vertex> &roots) {
int N = g.numVertices();

ancestorHeights.resize(N);
std::vector<Vertex> parents(N);
maxHIndices.resize(N);
std::vector<Vertex> vertices; vertices.reserve(N);
indices.resize(N);

Word currentIndex = 1;
for(int ri = 0; ri < (int)roots.size(); ri ++) {
Vertex root = roots[ri];
parents[root] = root;
vertices.push_back(root);
}
while(!vertices.empty()) {
Vertex v = vertices.back(); vertices.pop_back();
indices[v] = currentIndex ++;
for(const Graph::To *it = g.edgesBegin(v); it != g.edgesEnd(v); ++ it) {
parents[it->to] = v;
vertices.push_back(it->to);
}
}

int head = 0, tail = roots.size();
vertices.resize(N);
for(int ri = 0; ri < (int)roots.size(); ri ++)
vertices[ri] = roots[ri];
while(head != tail) {
Vertex v = vertices[head ++];
for(const Graph::To *it = g.edgesBegin(v); it != g.edgesEnd(v); ++ it)
vertices[tail ++] = it->to;
}

for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it)
maxHIndices[*it] = indices[*it];
for(std::vector<Vertex>::const_reverse_iterator it = vertices.rbegin(); it != vertices.rend(); ++ it) {
Vertex v = *it, parent = parents[v];
if(lowestOneBit(maxHIndices[parent]) < lowestOneBit(maxHIndices[v]))
maxHIndices[parent] = maxHIndices[v];
}

for(int ri = 0; ri < (int)roots.size(); ri ++) {
Vertex root = roots[ri];
ancestorHeights[root] = 0;
}
for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it) {
Vertex v = *it;
ancestorHeights[v] = ancestorHeights[parents[v]] | lowestOneBit(maxHIndices[v]);
}

pathParents.swap(parents);
for(int ri = 0; ri < (int)roots.size(); ri ++) {
Vertex root = roots[ri];
pathParents[indices[root]-1] = root;
}
for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it) {
Vertex v = *it;
for(const Graph::To *jt = g.edgesBegin(v); jt != g.edgesEnd(v); ++ jt) {
if(maxHIndices[v] != maxHIndices[jt->to])
pathParents[indices[jt->to]-1] = v;
else
pathParents[indices[jt->to]-1] = pathParents[indices[v]-1];
}
}
}

Vertex query(Vertex v, Vertex u) const {
Word Iv = maxHIndices[v], Iu = maxHIndices[u];
Word hIv = lowestOneBit(Iv), hIu = lowestOneBit(Iu);
Word hbMask = highestOneBitMask((Iv ^ Iu) | hIv | hIu);
Word j = lowestOneBit(ancestorHeights[v] & ancestorHeights[u] & ~hbMask);
Vertex x, y;
if(j == hIv) x = v;
else {
Word kMask = highestOneBitMask(ancestorHeights[v] & (j-1));
x = pathParents[(indices[v] & ~kMask | (kMask+1))-1];
}
if(j == hIu) y = u;
else {
Word kMask = highestOneBitMask(ancestorHeights[u] & (j-1));
y = pathParents[(indices[u] & ~kMask | (kMask+1))-1];
}
return indices[x] < indices[y] ? x : y;
}
};



vector<int> t_parent;
vi t_seq; vector<bool> t_sign;
vector<int> t_left, t_right;

void tree_signedeulertour(const vector<vi> &g, int root) {
int n = g.size();
t_parent.assign(n, -1);
t_left.assign(n, -1);
t_right.assign(n, -1);
t_seq.assign(n * 2, -1);
t_sign.assign(n * 2, false);
int pos = 0;

vector<int> stk; stk.push_back(root);
while(!stk.empty()) {
int i = stk.back(); stk.pop_back();
if(i < 0) {
i = -i - 1;
t_seq[pos] = i;
t_sign[pos] = true;
pos ++;
t_right[i] = pos;
continue;
}
t_left[i] = pos;
t_seq[pos] = i;
t_sign[pos] = false;
pos ++;

stk.push_back(-(i+1));
for(int j = (int)g[i].size()-1; j >= 0; j --) {
int c = g[i][j];
if(t_parent[c] == -1 && c != root)
stk.push_back(c);
else
t_parent[i] = c;
}
}
}

struct FenwickTreeXor {
typedef int T;
vector<T> v;
void init(int n) { v.assign(n, 0); }
void add(int i, T x) {
for(; i < (int)v.size(); i |= i+1) v[i] ^= x;
}
T sum(int i) const {
T r = 0;
for(-- i; i >= 0; i = (i & (i+1)) - 1) r ^= v[i];
return r;
}
T sum(int left, int right) const {
return sum(right) ^ sum(left);
}
};


int main() {
typedef SchieberVishkinLCA::Graph Graph;

int T;
scanf("%d", &T);
assert(1 <= T && T <= 10);
rep(ii, T) {
int N;
scanf("%d", &N);
assert(1 <= N && N <= 100000);
vector<int> A(N);
rep(i, N) {
scanf("%d", &A[i]);
assert(1 <= A[i] && A[i] <= 1000000000);
}
vector<vi> g(N);
rep(i, N-1) {
int u, v;
scanf("%d%d", &u, &v), -- u, -- v;
assert(0 <= u && u < N && 0 <= v && v < N);
g[u].push_back(v);
g[v].push_back(u);
}
tree_signedeulertour(g, 0);

vector<Graph::Edge> edges;
reu(i, 1, N)
edges.push_back(Graph::Edge(t_parent[i], i));
Graph gg; gg.init(N, edges);
SchieberVishkinLCA lca; lca.build(gg, 0);

FenwickTreeXor ft;
ft.init(t_seq.size());
rep(i, t_seq.size())
ft.add(i, A[t_seq[i]]);

int Q;
scanf("%d", &Q);
assert(1 <= Q && Q <= 100000);
rep(jj, Q) {
int t;
scanf("%d", &t);
assert(1 <= t && t <= 2);
if(t == 1) {
int u, v;
scanf("%d%d", &u, &v), -- u;
assert(0 <= u && u < N);
assert(1 <= v && v <= 1000000000);
ft.add(t_left[u], A[u] ^ v);
ft.add(t_right[u] - 1, A[u] ^ v);
A[u] = v;
}else if(t == 2) {
int u, v;
scanf("%d%d", &u, &v), -- u, -- v;
assert(0 <= u && u < N && 0 <= v && v < N);
int w = lca.query(u, v);
int ans = 0;
ans ^= ft.sum(t_left[w], t_left[u] + 1);
ans ^= ft.sum(t_left[w] + 1, t_left[v] + 1);
printf("%d\n", ans);
}
}
}
return 0;
}