Problem:
H - Bit Operation Game

N 頂点の根付き木が与えられる。
頂点には 0 から N − 1 の番号がついており、0番目の頂点が根を表す。
根には T = 0 が、それ以外の頂点には

T=T&X

T=T&Y

T=T|X

T=T|Y

T=T^X

T=T^Y

のいずれかの操作が書かれている。
ここでの演算子 &, |, ^ はそれぞれビット演算子 and, or, xor, を意味する。

A君とB君はこの木を使って以下のゲームを M 回行った。
二人は根からスタートし、子頂点を選び進むという操作を、A君から始め葉に到達するまで交互に行う。
通ったノードに書かれている操作を、通った順に適用した時の、最終的な T の値がスコアになる。
B君はできるだけスコアを小さくしたいと考えており、またA君は大きくしたいと考えている。
M回のゲームの X, Y の値が与えられるので、二人が最適な選択をした時の各ゲームのスコアを出力せよ。

Constraints

1 ≤ N ≤ 100000

1 ≤ M ≤ 100000

0 ≤ X, Y < 2^{16}

Input Format

入力は以下の形式で標準入力から与えられる。

N M
o_1
o_2
...
o_{N−1}
u_1 v_1
u_2 v_2
...
u_{N−1} v_{N−1}
X_1 Y_1
X_2 Y_2
...
X_M Y_M

1 行目には木の頂点数 N と、行われるゲーム数を表す整数 M が入力される。

2 行目から N 行目にかけて、1 ... N−1 番目の頂点に書かれている操作が入力される。

さらに続けて N−1 行に、各辺により繋がれる 2 頂点の番号が入力される。

最後に M 回のゲームにおける X, Y の値が M 行に渡り入力される。

Output Format

各ゲームでの最終的な T の値をそれぞれ M 行に出力せよ。

Sample Input 1

6 3
T=T|X
T=T|Y
T=T|Y
T=T^Y
T=T&X
0 1
0 2
1 3
1 4
2 5
5 6
3 5
0 0

Sample Output 1

4
6
0

X = 5, Y = 6 の場合、頂点 0 -> 2 -> 5 と進み、T = 5 & 6 = 4 になります

X = 3, Y = 5 の場合、頂点 0 -> 1 -> 4 と進み、T = 3 ^ 5 = 6 になります

X = 0, Y = 0 の場合、どこを通っても T は 0 から変化しません

Solution in Rust (judge verdict: Accepted)

#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;
use std::io::{Read, Write, BufWriter};
#[allow(dead_code)]
fn getline() -> String {
    let mut ret = String::new();
    std::io::stdin().read_line(&mut ret).ok().unwrap();
    ret
}
fn get_word<R: std::io::Read>(br: &mut std::io::BufReader<R>) -> String {
    let mut u8b: [u8; 1] = [0];
    loop {
        let mut buf: Vec<u8> = Vec::with_capacity(16);
        loop {
            let res = br.read(&mut u8b);
            if res.unwrap_or(0) == 0 || u8b[0] <= b' ' {
                break;
            } else {
                buf.push(u8b[0]);
            }
        }
        if buf.len() >= 1 {
            let ret = String::from_utf8(buf).unwrap();
            return ret;
        }
    }
}

#[allow(dead_code)]
fn get<R: std::io::Read, T: std::str::FromStr>(br: &mut std::io::BufReader<R>) -> T { get_word(br).parse().ok().unwrap() }

/**
 * Returns the least index of elements that are modified, wrapped with Some.
 * If the entire array is reversed, it returns None instead.
 * v's elements must be pairwise distinct.
 */
fn next_permutation<T: Ord>(v: &mut [T]) -> Option<usize> {
    let mut tail_dec: usize = 1;
    let n = v.len();
    while tail_dec < n {
        if v[n - tail_dec - 1] > v[n - tail_dec] {
            tail_dec += 1;
        } else {
            break;
        }
    }
    // v[n - tail_dec .. n] is strictly decreasing
    if tail_dec < n {
        let x = n - tail_dec - 1;
        let mut y = n;
        {
            let pivot = &v[x];
            for i in (n - tail_dec .. n).rev() {
                if v[i] > *pivot {
                    y = i;
                    break;
                }
            }
            assert!(y < n);
        }
        v.swap(x, y);
    }
    v[n - tail_dec .. n].reverse();
    if tail_dec < n {
        Some(n - tail_dec - 1)
    } else {
        None
    }
}

#[derive(Clone, Copy)]
enum Op {
    And,
    Or,
    Xor,
}

#[derive(Clone, Copy)]
enum Var { X, Y }

fn perform(val: usize, op: (Op, Var)) -> usize {
    let aff = match op.1 {
        Var::X => 6, // **.
        Var::Y => 5, // *.*
    };
    match op.0 {
        Op::And => val & aff,
        Op::Or => val | aff,
        Op::Xor => val ^ aff,
    }
}

fn dfs(v: usize, par: usize, maxim: bool, val: usize,
       g: &[Vec<usize>], inv: &[usize; 8],
       kind: &[(Op, Var)]) -> usize {
    let mut num_ch = 0;
    let mut ch = if maxim { (0, 0) } else { (100, 100) };
    for &w in &g[v] {
        if w == par { continue; }
        let next_val = perform(val, kind[w]);
        let sub = dfs(w, v, !maxim, next_val, g, inv, kind);
        ch = if maxim {
            max(ch, (inv[sub], sub))
        } else {
            min(ch, (inv[sub], sub))
        }; 
        num_ch += 1;
    }
    if num_ch == 0 {
        return val;
    }
    ch.1
}

fn solve() {
    let stdin = std::io::stdin();
    let mut br = std::io::BufReader::new(stdin.lock());
    let out = std::io::stdout();
    let mut out = BufWriter::new(out.lock());
    macro_rules! puts {
        ($format:expr) => (write!(out,$format).unwrap());
        ($format:expr, $($args:expr),+) => (write!(out,$format,$($args),*).unwrap())
    }
    let n = get(&mut br);
    let m: usize = get(&mut br);
    let mut o: Vec<_> = (1 .. n).map(|_| get_word(&mut br)).collect();
    o.insert(0, "".to_string());
    let mut kind = vec![(Op::And, Var::X); n];
    for i in 1 .. n {
        let chs: Vec<char> = o[i].chars().collect();
        let op = match chs[3] {
            '&' => Op::And,
            '|' => Op::Or,
            '^' => Op::Xor,
            _ => panic!(),
        };
        let v = match chs[4] {
            'X' => Var::X,
            'Y' => Var::Y,
            _ => panic!(),
        };
        kind[i] = (op, v);
    }
    let mut g = vec![Vec::new(); n];
    for _ in 0 .. n - 1 {
        let u = get::<_, usize>(&mut br);
        let v = get::<_, usize>(&mut br);
        g[u].push(v);
        g[v].push(u);
    }
    // 6! brute force
    let mut perm = [0; 8];
    for i in 0 .. 8 {
        perm[i] = i;
    }
    let mut hm = HashMap::new();
    loop {
        let mut inv = [0; 8];
        for i in 0 .. 8 { inv[perm[i]] = i; }
        let mut ok = true;
        for i in 0 .. 8 {
            for j in i + 1 .. 8 {
                if (i & j) == i {
                    if inv[i] > inv[j] {
                        ok = false;
                        break;
                    }
                }
            }
        }
        if ok {
            let ans = dfs(0, n + 1, true, 0, &g, &inv, &kind);
            let mut key = [0; 6];
            key.copy_from_slice(&perm[1..7]);
            hm.insert(key, ans);
        }
        if let None = next_permutation(&mut perm[1..7]) { break; }
    }
    for _ in 0 .. m {
        let x: i32 = get(&mut br);
        let y: i32 = get(&mut br);
        let mut pool = Vec::new();
        pool.push((!x & y, 1));
        pool.push((x & !y, 2));
        pool.push((x ^ y, 3));
        pool.push((x & y, 4));
        pool.push((y, 5));
        pool.push((x, 6));
        pool.sort();
        let mut key = [0; 6];
        for i in 0 .. 6 { key[i] = pool[i].1; }
        let ans = hm.get(&key).unwrap();
        let tbl = [0, !x & y, x & !y, x ^ y, x & y, y, x, x | y];
        puts!("{}\n", tbl[*ans]);
    }
}

fn main() {
    // In order to avoid potential stack overflow, spawn a new thread.
    let stack_size = 104_857_600; // 100 MB
    let thd = std::thread::Builder::new().stack_size(stack_size);
    thd.spawn(|| solve()).unwrap().join().unwrap();
}