note

solution

Euler tourして区間操作/点取得のsegment木で管理して$O(n \log n)$。 あるいは2回DFSで$O(n)$。どちらもやってることは同じ。

implementation

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; (i) < (int)(n); ++ (i))
using namespace std;

template <class OperatorMonoid>
struct dual_segment_tree {
    typedef typename OperatorMonoid::underlying_type operator_type;
    typedef typename OperatorMonoid::target_type underlying_type;
    int n;
    vector<operator_type> f;
    vector<underlying_type> a;
    const OperatorMonoid op;
    dual_segment_tree() = default;
    dual_segment_tree(int a_n, underlying_type initial_value, OperatorMonoid const & a_op = OperatorMonoid()) : op(a_op) {
        n = 1; while (n < a_n) n *= 2;
        a.resize(n, initial_value);
        f.resize(n-1, op.unit());
    }
    underlying_type point_get(int i) { // 0-based
        underlying_type acc = a[i];
        for (i = (i+n)/2; i > 0; i /= 2) { // 1-based
            acc = op.apply(f[i-1], acc);
        }
        return acc;
    }
    void range_apply(int l, int r, operator_type z) { // 0-based, [l, r)
        assert (0 <= l and l <= r and r <= n);
        range_apply(0, 0, n, l, r, z);
    }
    void range_apply(int i, int il, int ir, int l, int r, operator_type z) {
        if (l <= il and ir <= r) { // 0-based
            if (i < f.size()) {
                f[i] = op.append(z, f[i]);
            } else {
                a[i-n+1] = op.apply(z, a[i-n+1]);
            }
        } else if (ir <= l or r <= il) {
            // nop
        } else {
            range_apply(2*i+1, il, (il+ir)/2, 0, n, f[i]);
            range_apply(2*i+2, (il+ir)/2, ir, 0, n, f[i]);
            f[i] = op.unit();
            range_apply(2*i+1, il, (il+ir)/2, l, r, z);
            range_apply(2*i+2, (il+ir)/2, ir, l, r, z);
        }
    }
};

enum op_t {
    OP_NOP = -1,
    OP_ZERO = 0,
    OP_ONE = 1,
    OP_FLIP = 2,
};
struct operator_monoid {
    typedef op_t underlying_type;
    typedef bool target_type;
    op_t unit() const {
        return OP_NOP;
    }
    op_t append(op_t a, op_t b) const {
        if (a == OP_NOP) {
            return b;
        } else if (a == OP_ZERO or a == OP_ONE) {
            return a;
        } else if (a == OP_FLIP) {
            if (b == OP_NOP) {
                return OP_FLIP;
            } else if (b == OP_ZERO) {
                return OP_ONE;
            } else if (b == OP_ONE) {
                return OP_ZERO;
            } else if (b == OP_FLIP) {
                return OP_NOP;
            }
        }
        assert (false);
    }
    bool apply(op_t a, bool b) const {
        if (a == OP_NOP) {
            return b;
        } else if (a == OP_ZERO) {
            return false;
        } else if (a == OP_ONE) {
            return true;
        } else if (a == OP_FLIP) {
            return not b;
        }
        assert (false);
    }
};

constexpr int IN = 1;
constexpr int AND = 2;
constexpr int OR = 3;
constexpr int XOR = 4;
constexpr int NOT = 5;
constexpr int root = 0;

int main() {
    // input
    int n; scanf("%d", &n);
    vector<array<int, 3> > g(n);
    int k = 0;
    REP (i, n) {
        char buf[16]; scanf("%s", buf);
        string s(buf);
        if (s == "IN") {
            scanf("%d", &g[i][1]);
            g[i][0] = IN;
            ++ k;
        } else if (s == "NOT") {
            scanf("%d", &g[i][1]);
            -- g[i][1];
            g[i][0] = NOT;
        } else {
            scanf("%d%d", &g[i][1], &g[i][2]);
            -- g[i][1];
            -- g[i][2];
            if (s == "AND") {
                g[i][0] = AND;
            } else if (s == "OR") {
                g[i][0] = OR;
            } else if (s == "XOR") {
                g[i][0] = XOR;
            } else {
                assert (false);
            }
        }
    }

    // solve
    vector<int> left(n);
    vector<int> right(n); {
        function<int (int, int)> go = [&](int i, int l) {
            left[i] = l;
            if (g[i][0] == IN) {
                right[i] = l + 1;
                return 1;
            } else if (g[i][0] == NOT) {
                int k = go(g[i][1], l);
                right[i] = l + k;
                return k;
            } else {
                int k = go(g[i][1], l);
                k += go(g[i][2], l + k);
                right[i] = l + k;
                return k;
            }
        };
        go(root, 0);
    }
    dual_segment_tree<operator_monoid> segtree(k, 0);
    function<bool (int)> go = [&](int i) {
        if (g[i][0] == IN) {
            segtree.range_apply(left[i], right[i], g[i][1] ? OP_ZERO : OP_ONE);
            return (bool)g[i][1];
        } else if (g[i][0] == NOT) {
            bool x = go(g[i][1]);
            segtree.range_apply(left[i], right[i], OP_FLIP);
            return not x;
        } else {
            int middle = right[g[i][1]];
            bool x = go(g[i][1]);
            bool y = go(g[i][2]);
            if (g[i][0] == AND) {
                if (not y) segtree.range_apply(left[i], middle, OP_ZERO);
                if (not x) segtree.range_apply(middle, right[i], OP_ZERO);
                return x and y;
            } else if (g[i][0] == OR) {
                if (y) segtree.range_apply(left[i], middle, OP_ONE);
                if (x) segtree.range_apply(middle, right[i], OP_ONE);
                return x or y;
            } else if (g[i][0] == XOR) {
                if (y) segtree.range_apply(left[i], middle, OP_FLIP);
                if (x) segtree.range_apply(middle, right[i], OP_FLIP);
                return x != y;
            }
            assert (false);
        }
    };
    go(root);

    // output
    REP (i, n) if (g[i][0] == IN) {
        printf("%d", segtree.point_get(left[i]));
    }
    printf("\n");
    return 0;
}