Problem:
Score : 150 points

Problem Statement

Gorillas in Kyoto University are good at math.
They are currently trying to solve problems to find the value of an expression that contains two functions, _ , ^.
Each of these functions takes two input values. _ function returns the smaller of the two input values and ^ function returns the larger.
Gorillas know that integers in the expression are non-negative and less than or equal to 99,
but can not find out the length of the expression until they read a terminal symbol ? that represents the end of the expression. The number of characters included in each expression is less than or equal to 1000, but they do not even know this fact.
Ai, a smart gorilla, noticed that she may be able to know the value of the expression even if they don't read the whole expression.

For example,

Assume you read the following sentence from the left.

^(41,3)?

When you read the sixth character, that is, when you read the following expression,

^(41,3

you can tell the second input value of the funcion is whether 3 or an integer between 30 and 39, and the value turns out 41.

Since Ai wants to solve problems earlier than other gorillas, she decided to solve the problems such that she reads as fewer characters as possible from the left.
For each expression, Find the value of the expression and the minimum number of characters Ai needs to read to know the value.

Constraints

1 \leq Q \leq 200

The number of characters each expression contains is less than or equal to 1000.

Input

The input consists of multiple test cases and is given from Standard Input in the following format:

Q
statement_1
...
statement_Q

Each statement_i (1 \leq i \leq Q) is given in the following BNF format.

<statement> ::= <expression> ?
<expression> ::= (^ | _) ( <expression> , <expression> ) | <number>
<number> :: = 0 | 1 | 2 | ... | 98 | 99

Output

Output consists of Q lines.
On line i (1 \leq i \leq Q), print the value of the expression and the number of character Ai needs to read for the test case i separated by space.

Sample Input 1

4
_(4,51)?
^(99,_(3,67))?
_(0,87)?
3?

Sample Output 1

4 5
99 4
0 3
3 2

For the first test case, when you read the fifth character, that is, when you read _(4,5, you will know the value is 4.

For the second test case, when you read the fourth character, that is, when you read ^(99, you will know the value is 99.

For the third test case, when you read the third character, that is, when you read _(0, you will know the value is 0.

For the fourth test case, you will not know the value is 3 untill you read the terminal symbol.

Sample Input 2

7
_(23,^(_(22,40),4))?
_(0,99)?
^(99,_(^(19,2),5))?
_(^(43,20),^(30,29))?
^(_(20,3),_(50,41))?
^(_(20,3),_(3,41))?
^(_(20,3),_(4,41))?

Sample Output 2

22 18
0 3
99 4
30 17
41 17
3 14
4 15

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.io.*;
import java.util.Arrays;
import java.util.StringJoiner;
import java.util.StringTokenizer;
import java.util.function.IntPredicate;

public class Main {

    public static void main(String[] args) {
        FastScanner sc = new FastScanner(System.in);
        PrintWriter pw = new PrintWriter(System.out);
        int Q = sc.nextInt();
        for (int i = 0; i < Q; i++) {
            String s = sc.next();
            pw.println( solve(s) );
        }
        pw.flush();
    }

    static String solve(String s) {
        Context context = new Context(s);
        Node node = parse(context);
        int idx = minimize(0, s.length(), x -> node.getMin(x) == node.getMax(x));
        return node.getMin(idx) + " " + (idx+1);
    }

    static int minimize(int lo, int hi, IntPredicate p) {
        while(lo < hi) {
            int x = ((hi - lo) >>> 1) + lo;
            if( p.test(x) ) {
                hi = x;
            } else {
                lo = x + 1;
            }
        }
        return lo;
    }

    static Node parse(Context context) {
        if( context.peek() == '^' || context.peek() == '_' ) {
            char f = context.poll();
            context.poll(); // L
            Node l = parse(context);
            context.poll(); // comma
            Node r = parse(context);
            context.poll(); // R
            return new Func(f, l, r);

        } else {
            int from = context.index();
            context.poll(); // digit
            if( Character.isDigit(context.peek()) ) {
                int to = context.index();
                context.poll(); // digit
                return new Number(context.s, from, to);

            } else {
                return new Number(context.s, from, from);
            }
        }
    }

    interface Node {
        int getMin(int idx);
        int getMax(int idx);
    }

    static class Number implements Node {

        String s;
        int from, to; // [from, to]

        public Number(String s, int from, int to) {
            this.s = s;
            this.from = from;
            this.to = to;
        }

        public int getMin(int idx) {
            if( idx < from ) {
                return 0;

            } else if( idx == from ) {
                char c = s.charAt(from);
                if( c == '0' ) {
                    // 03とかそういうのがないので0が確定する
                    return 0;
                } else {
                    return (c - '0');
                }

            } else {
                // 確定
                char c = s.charAt(from);
                if( from != to ) {
                    char d = s.charAt(to);
                    return (c - '0') * 10 + (d - '0');
                } else {
                    return (c - '0');
                }
            }
        }

        public int getMax(int idx) {
            if( idx < from ) {
                return 99;

            } else if( idx == from ) {
                char c = s.charAt(from);
                if( c == '0' ) {
                    // 03とかそういうのがないので0が確定する
                    return 0;
                } else {
                    // 3?の可能性
                    return (c - '0') * 10 + 9;
                }

            } else {
                // 確定
                char c = s.charAt(from);
                if( from != to ) {
                    char d = s.charAt(to);
                    return (c - '0') * 10 + (d - '0');
                } else {
                    return (c - '0');
                }
            }
        }
    }

    static class Func implements Node {

        private char f;
        private Node l;
        private Node r;

        public Func(char f, Node l, Node r) {
            this.f = f;
            this.l = l;
            this.r = r;
        }

        public int getMin(int idx) {
            int lv = l.getMin(idx);
            int rv = r.getMin(idx);
            if( f == '^' ) {
                return Math.max(lv, rv);

            } else {
                return Math.min(lv, rv);
            }
        }

        public int getMax(int idx) {
            int lv = l.getMax(idx);
            int rv = r.getMax(idx);
            if( f == '^' ) {
                return Math.max(lv, rv);

            } else {
                return Math.min(lv, rv);
            }
        }
    }

    static class Context {

        private String s;
        private int i;

        public Context(String s) {
            this.s = s;
        }

        public char peek() {
            return s.charAt(i);
        }

        public int index() {
            return i;
        }

        public char poll() {
            return s.charAt(i++);
        }
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        FastScanner(InputStream in) {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        String next() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        String nextLine() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    return reader.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken("\n");
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        int[] nextIntArray(int n) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++) a[i] = nextInt();
            return a;
        }

        int[] nextIntArray(int n, int delta) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++) a[i] = nextInt() + delta;
            return a;
        }

        long[] nextLongArray(int n) {
            long[] a = new long[n];
            for (int i = 0; i < n; i++) a[i] = nextLong();
            return a;
        }
    }

    static void writeLines(int[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (int a : as) pw.println(a);
        pw.flush();
    }

    static void writeLines(long[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (long a : as) pw.println(a);
        pw.flush();
    }

    static void writeSingleLine(int[] as) {
        PrintWriter pw = new PrintWriter(System.out);
        for (int i = 0; i < as.length; i++) {
            if (i != 0) pw.print(" ");
            pw.print(as[i]);
        }
        pw.println();
        pw.flush();
    }

    static int max(int... as) {
        int max = Integer.MIN_VALUE;
        for (int a : as) max = Math.max(a, max);
        return max;
    }

    static int min(int... as) {
        int min = Integer.MAX_VALUE;
        for (int a : as) min = Math.min(a, min);
        return min;
    }

    static void debug(Object... args) {
        StringJoiner j = new StringJoiner(" ");
        for (Object arg : args) {
            if (arg == null) j.add("null");
            else if (arg instanceof int[]) j.add(Arrays.toString((int[]) arg));
            else if (arg instanceof long[]) j.add(Arrays.toString((long[]) arg));
            else if (arg instanceof double[]) j.add(Arrays.toString((double[]) arg));
            else if (arg instanceof Object[]) j.add(Arrays.toString((Object[]) arg));
            else j.add(arg.toString());
        }
        System.err.println(j.toString());
    }

    static void printSingleLine(int[] array) {
        PrintWriter pw = new PrintWriter(System.out);
        for (int i = 0; i < array.length; i++) {
            if (i != 0) pw.print(" ");
            pw.print(array[i]);
        }
        pw.println();
        pw.flush();
    }

    static int lowerBound(int[] array, int value) {
        int lo = 0, hi = array.length, mid;
        while (lo < hi) {
            mid = (hi + lo) / 2;
            if (array[mid] < value) lo = mid + 1;
            else hi = mid;
        }
        return lo;
    }

    static int upperBound(int[] array, int value) {
        int lo = 0, hi = array.length, mid;
        while (lo < hi) {
            mid = (hi + lo) / 2;
            if (array[mid] <= value) lo = mid + 1;
            else hi = mid;
        }
        return lo;
    }
}