#include <bits/stdc++.h>
using namespace std;
const long long int mod = 1000000007;
struct lazy_segtree {
  int n;
  vector<int> data_min;
  vector<int> data_max;
  vector<int> lazy;
  lazy_segtree(const int s) { init(s); }
  lazy_segtree(const vector<int> &v) {
    int s = v.size();
    init(s);
    for (int i = 0; i < s; i++) {
      data_min[i + n - 1] = v[i];
      data_max[i + n - 1] = v[i];
    }
    for (int i = n - 2; i >= 0; i--) {
      data_min[i] = min(data_min[i * 2 + 1], data_min[i * 2 + 2]);
      data_max[i] = max(data_max[i * 2 + 1], data_max[i * 2 + 2]);
    }
  }
  void init(const int s) {
    n = 1;
    while (n < s) n <<= 1;
    data_min = vector<int>(2 * n - 1);
    data_max = vector<int>(2 * n - 1);
    lazy = vector<int>(2 * n - 1);
  }
  void evaluate(int p) {
    if (lazy[p] != 0) {
      data_min[p] += lazy[p];
      data_max[p] += lazy[p];
      if (p <= n - 2) {
        lazy[p * 2 + 1] += lazy[p];
        lazy[p * 2 + 2] += lazy[p];
      }
      lazy[p] = 0;
    }
  }
  void update(int l, int r, int v, int p = 0, int a = 0, int b = -1) {
    if (b < 0) b = n;
    evaluate(p);
    if (r <= a || b <= l) return;
    if (l <= a && b <= r) {
      lazy[p] += v;
      evaluate(p);
    } else {
      update(l, r, v, p * 2 + 1, a, (a + b) / 2);
      update(l, r, v, p * 2 + 2, (a + b) / 2, b);
      data_min[p] = min(data_min[p * 2 + 1], data_min[p * 2 + 2]);
      data_max[p] = max(data_max[p * 2 + 1], data_max[p * 2 + 2]);
    }
    return;
  }
  int query_max(int l, int r, int p = 0, int a = 0, int b = -1) {
    if (b < 0) b = n;
    if (r <= a || b <= l) return 0x80000000;
    evaluate(p);
    if (l <= a && b <= r) return data_max[p];
    int vl = query_max(l, r, p * 2 + 1, a, (a + b) / 2);
    int vr = query_max(l, r, p * 2 + 2, (a + b) / 2, b);
    return max(vl, vr);
  }
  int query_min(int l, int r, int p = 0, int a = 0, int b = -1) {
    if (b < 0) b = n;
    if (r <= a || b <= l) return 0x7fffffff;
    evaluate(p);
    if (l <= a && b <= r) return data_min[p];
    int vl = query_min(l, r, p * 2 + 1, a, (a + b) / 2);
    int vr = query_min(l, r, p * 2 + 2, (a + b) / 2, b);
    return min(vl, vr);
  }
};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int n;
  cin >> n;
  string s;
  cin >> s;
  int maxPos = 0;
  int p = 0;
  for (int i = 0; i < n; i++) {
    if (s[i] == 'L' && p > 0)
      p--;
    else if (s[i] == 'R')
      p++;
    if (p > maxPos) maxPos = p;
  }
  int k = 1;
  while (k <= maxPos) k <<= 1;
  lazy_segtree rd(k);
  vector<char> buf(k);
  vector<int> ans(n);
  p = 0;
  for (int i = 0; i < n; i++) {
    if (s[i] == 'L') {
      if (p > 0) p--;
    } else if (s[i] == 'R')
      p++;
    else if (s[i] == '(') {
      if (buf[p] == ')')
        rd.update(p, k, 2);
      else if (buf[p] != '(')
        rd.update(p, k, 1);
      buf[p] = '(';
    } else if (s[i] == ')') {
      if (buf[p] == '(')
        rd.update(p, k, -2);
      else if (buf[p] != ')')
        rd.update(p, k, -1);
      buf[p] = ')';
    } else {
      if (buf[p] == '(')
        rd.update(p, k, -1);
      else if (buf[p] == ')')
        rd.update(p, k, 1);
      buf[p] = s[i];
    }
    if (rd.query_min(0, k) != 0 || rd.query_min(k - 1, k) != 0)
      ans[i] = -1;
    else
      ans[i] = rd.query_max(0, k);
  }
  for (auto &x : ans) cout << x << " ";
  cout << endl;
  return 0;
}
