#include <vector>
#include <iostream>
#include <utility>
#include <algorithm>
#include <string>
#include <deque>
#include <tuple>
#include <queue>
#include <functional>
#include <cmath>
#include <iomanip>
#include <set>
#include <map>
#include <numeric>
#include <unordered_map>
#include <unordered_set>
#include <complex>
#include <array>
//cin.sync_with_stdio(false);
//streambuf
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
using vi = vector<int>;
using vll = vector<ll>;
using vpii = vector<pii>;
using ti3 = tuple<int, int, int>;
using vti3 = vector<ti3>;
template<class T, class T2> using umap = unordered_map<T, T2>;
template<class T> using uset = unordered_set<T>;
template<class T> void cmin(T &a, const T&b) { if (a > b)a = b; }
template<class T> void cmax(T &a, const T&b) { if (a < b)a = b; }
#define ALL(a) a.begin(),a.end()
#define rep(i,a) for(int i=0;i<a;i++)
#define rep1(i,a) for(int i=1;i<=a;i++)
const ll mod = 1000000007;
#ifndef INT_MAX
const int INT_MAX = numeric_limits<signed>().max();
#endif
template<class T>using heap = priority_queue<T, vector<T>, greater<T>>;
template<class T>using pque = priority_queue<T, vector<T>, function<T(T, T)>>;
template <class T>
inline void hash_combine(size_t & seed, const T & v) {
	hash<T> hasher;
	seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std {

	template<typename S, typename T> struct hash<pair<S, T>> {
		inline size_t operator()(const pair<S, T> & v) const {
			size_t seed = 0;
			hash_combine(seed, v.first);
			hash_combine(seed, v.second);
			return seed;
		}
	};
	// Recursive template code derived from Matthieu M.
	template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
	struct HashValueImpl
	{
		static void apply(size_t& seed, Tuple const& tuple)
		{
			HashValueImpl<Tuple, Index - 1>::apply(seed, tuple);
			hash_combine(seed, std::get<Index>(tuple));
		}
	};

	template <class Tuple>
	struct HashValueImpl<Tuple, 0>
	{
		static void apply(size_t& seed, Tuple const& tuple)
		{
			hash_combine(seed, std::get<0>(tuple));
		}
	};

	template <typename ... TT>
	struct hash<std::tuple<TT...>>
	{
		size_t
			operator()(std::tuple<TT...> const& tt) const
		{
			size_t seed = 0;
			HashValueImpl<std::tuple<TT...> >::apply(seed, tt);
			return seed;
		}

	};
}
umap<ti3, ll> memo;
ll pow(ll base, ll i, ll mod) {
	ll a = 1;
	while (i) {
		if (i & 1) {
			a *= base;
			a %= mod;
		}
		base *= base;
		base %= mod;
		i /= 2;
	}
	return a;
}
class unionfind {
	vector<int> par, rank, size_;//速度ではなくメモリ効率を考えるならrankのかわりにsizeを使う
public:
	unionfind(int n) :par(n), rank(n), size_(n, 1) {
		iota(ALL(par), 0);
	}
	int find(int x) {
		if (par[x] == x)return x;
		return par[x] = find(par[x]);
	}
	void unite(int x, int y) {
		x = find(x), y = find(y);
		if (x == y)return;
		if (rank[x] < rank[y])swap(x, y);
		par[y] = x;
		size_[x] += size_[y];
		if (rank[x] == rank[y])rank[x]++;
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
	int size(int x) {
		return size_[find(x)];
	}
};
ll gcd(ll a, ll b) {
	while (b) {
		ll c = a%b;
		a = b;
		b = c;
	}
	return a;
}
ll lcm(ll a, ll b) {
	return a / gcd(a, b)*b;
}
int popcnt(unsigned long long a) {
	a = (a & 0x5555555555555555) + (a >> 1 & 0x5555555555555555);
	a = (a & 0x3333333333333333) + (a >> 2 & 0x3333333333333333);
	a = (a & 0x0f0f0f0f0f0f0f0f) + (a >> 4 & 0x0f0f0f0f0f0f0f0f);
	a = (a & 0x00ff00ff00ff00ff) + (a >> 8 & 0x00ff00ff00ff00ff);
	a = (a & 0x0000ffff0000ffff) + (a >> 16 & 0x0000ffff0000ffff);
	return (a & 0xffffffff) + (a >> 32);
}
template<class T, class Func = function<T(T, T)>>
class segtree {
	vector<T> obj;
	int offset;
	Func updater;
	T e;
	int bufsize(int num) {
		int i = 1;
		for (; num >i; i <<= 1);
		offset = i - 1;
		return (i << 1) - 1;
	}
	T query(int a, int b, int k, int l, int r) {
		if (r <= a || b <= l)return e;
		if (a <= l && r <= b)return obj[k];
		else return updater(query(a, b, k * 2 + 1, l, (l + r) / 2), query(a, b, k * 2 + 2, (l + r) / 2, r));
	}
public:
	T query(int a, int b) {//[a,b)
		return query(a, b, 0, 0, offset + 1);
	}
	void updateall(int l = 0, int r = -1) {
		if (r < 0)r = offset + 1;
		l += offset, r += offset;
		do {
			l = l - 1 >> 1, r = r - 1 >> 1;
			for (int i = l; i < r; i++)obj[i] = updater(obj[i * 2 + 1], obj[i * 2 + 2]);
		} while (r);
	}
	void update(int k, T &a) {
		k += offset;
		obj[k] = a;
		while (k) {
			k = k - 1 >> 1;
			obj[k] = updater(obj[k * 2 + 1], obj[k * 2 + 2]);
		}
	}
	segtree(int n, T e, const Func &updater_ = Func()) :obj(bufsize(n), e), e(e), updater(updater_) {}
	segtree(vector<T> &vec, T e, const Func &updater = Func()) :obj(bufsize(vec.size()), e), e(e), updater(updater) {
		copy(vec.begin(), vec.end(), obj.begin() + offset);
		updateall();
	}
	typename vector<T>::reference operator[](int n) {
		return obj[n + offset];
	}
};
int ans;
void evalution(vector<array<int, 5>> &a) {
	for (auto it = a.rbegin(); it < --a.rend(); it++) {
		if ((*it)[0] & 6) {
			int pos = (*(it+1))[0] & 2;
			pos++;
			if ((*it)[0] & 1) {
				(*(it + 1))[pos] = max((*it)[1], (*it)[3]);
				(*(it + 1))[pos + 1] = max((*it)[2], (*it)[4]);
			}
			else{
				(*(it + 1))[pos] = min((*it)[1], (*it)[3]);
				(*(it + 1))[pos + 1] = min((*it)[2], (*it)[4]);
			}
		}
	}
}
int main() {
	int q;
	cin >> q;
	for (; q; q--) {
		vector<array<int,5>> sk;
		string s;
		cin >> s;
		int cnt = 0;
		bool n2 = 0;
		bool end = 0;
		sk.push_back({ 0,0,99,0,99 });
		for (; cnt < s.size();cnt++) {
			switch (s[cnt]) {
			case '_':
				sk.push_back({ 4, 0, 99,0,99 });
				cnt++;
				break;
			case '^':
				sk.push_back({ 5,0,99 ,0,99});
				cnt++;
				break;
			case '?':
				end = 1;
				break;
			case ',':
				sk.back()[0] += 2;
				if (n2) {
					sk.back()[2] = sk.back()[1];
					evalution(sk);
					n2 = 0;
					if (sk[0][1] == sk[0][2])end = 1;
				}
				break;
			case ')':
				sk.back()[4] = sk.back()[3];
				evalution(sk);
				if (sk[0][1] == sk[0][2])end=1;
				sk.pop_back();
				n2 = 0;
				break;
			case '0':
				if (!n2) {
					int pos = sk.back()[0] & 2;
					pos++;
					sk.back()[pos] = sk.back()[pos + 1] = 0;
					evalution(sk);
					if (sk[0][1] == sk[0][2])end = 1;
					break;
				}
			default:
			{
				int pos = sk.back()[0] & 2;
				pos++;
				if (!n2) {
					sk.back()[pos] = s[cnt]-'0';
					sk.back()[pos + 1] = (s[cnt]-'0') * 10 + 9;
					n2 = 1;
					evalution(sk);
					if (sk[0][1] == sk[0][2])end = 1, n2 = 0;
				}
				else {
					sk.back()[pos]=sk.back()[pos + 1] = sk.back()[pos] * 10 + s[cnt]-'0';
					evalution(sk);
					if (sk[0][1] == sk[0][2])end = 1;
					n2 = 0;
					break;
				}
			}
			}
			if (end)break;
		}
		cout << sk[0][1] << " " << cnt+1 << endl;
	}
}


Measured memory_bytes: 384