#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
typedef pair<int, int> pii;
typedef pair<pii, pii> ppi;
ppi seg[4 * maxn];
int mark[maxn];
void push(int index, int left, int right) {
    seg[index].first.first += seg[index].second.second;
    seg[index].first.second += seg[index].second.second;
    seg[index].second.first += (right - left + 1) * seg[index].second.second;
    if (left != right) {
        int mid = (left + right) / 2;
        seg[2 * index].second.second += seg[index].second.second;
        seg[2 * index + 1].second.second += seg[index].second.second;
        push(2 * index, left, mid); push(2 * index + 1, mid + 1, right);
    }
    seg[index].second.second = 0;
}
void update(int index, int left, int right, int lo, int hi, int val) {
    push(index, left, right);
    if (lo <= left && right <= hi) {
        seg[index].second.second += val;
        push(index, left, right);
        return;
    }
    int mid = (left + right) / 2;
    if (hi <= mid) update(2 * index, left, mid, lo, hi, val);
    else if (lo > mid) update(2 * index + 1, mid + 1, right, lo, hi, val);
    else {
        update(2 * index, left, mid, lo, hi, val); update(2 * index + 1, mid + 1, right, lo, hi, val);
    }
    seg[index].first.first = max(seg[2 * index].first.first, seg[2 * index + 1].first.first);
    seg[index].first.second = min(seg[2 * index].first.second, seg[2 * index + 1].first.second);
    seg[index].second.first = seg[2 * index].second.first + seg[2 * index + 1].second.first;
}
int query(int index, int left, int right, int pos) {
    push(index, left, right);
    if (left == right) {
        return seg[index].second.first == 0 && seg[1].first.second == 0? seg[1].first.first: -1;
    }
    int mid = (left + right) / 2;
    if (pos <= mid) return query(2 * index, left, mid, pos);
    return query(2 * index + 1, mid + 1, right, pos);
}
int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    int n; cin >> n;
    string s; cin >> s;
    int cursor = 0, bound = 0, cur = 0;
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cur;
        else if (s[i] == 'L') --cur;
        bound = max(bound, cur);
    }
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cursor;
        else if (s[i] == 'L') cursor = max(0, cursor - 1);
        else if (s[i] == '(' && mark[cursor] != 1) {
            update(1, 0, bound, cursor, bound, 1 - mark[cursor]);
            mark[cursor] = 1;
        } else if (s[i] == ')' && mark[cursor] != -1) {
            update(1, 0, bound, cursor, bound, -1 - mark[cursor]);
            mark[cursor] = -1;
        } else if (isalpha(s[i]) && mark[cursor]) {
            update(1, 0, bound, cursor, bound, -mark[cursor]);
            mark[cursor] = 0;
        }
        cout << query(1, 0, bound, bound) << ' ';
    }
    cout << '\n';
    return 0;
}


#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e6;
pii seg[4 * maxn];
int mark[maxn], lazy[4 * maxn];
void push(int index, int left, int right) {
    seg[index].first += lazy[index];
    seg[index].second += lazy[index];
    if (left != right) {
        lazy[2 * index] += lazy[index];
        lazy[2 * index + 1] += lazy[index];
    }
    lazy[index] = 0;
}
void update(int index, int left, int right, int lo, int hi, int val) {
    push(index, left, right);
    if (lo > right || hi < left) return;
    if (lo <= left && right <= hi) {
        lazy[index] += val;
        push(index, left, right);
        return;
    }
    int mid = (left + right) / 2;
    update(2 * index, left, mid, lo, hi, val); update(2 * index + 1, mid + 1, right, lo, hi, val);
    seg[index].first = max(seg[2 * index].first, seg[2 * index + 1].first);
    seg[index].second = min(seg[2 * index].second, seg[2 * index + 1].second);
}
int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    int n; cin >> n;
    string s; cin >> s;
    int cursor = 0, sum = 0;
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cursor;
        else if (s[i] == 'L') cursor = max(0, cursor - 1);
        else if (s[i] == '(' && mark[cursor] != 1) {
            update(1, 0, maxn, cursor, maxn, 1 - mark[cursor]);
            sum += 1 - mark[cursor];
            mark[cursor] = 1;
        } else if (s[i] == ')' && mark[cursor] != -1) {
            update(1, 0, maxn, cursor, maxn, -1 - mark[cursor]);
            sum += -1 - mark[cursor];
            mark[cursor] = -1;
        } else if (isalpha(s[i]) && mark[cursor]) {
            update(1, 0, maxn, cursor, maxn, -mark[cursor]);
            sum += -mark[cursor];
            mark[cursor] = 0;
        }
        cout << (sum == 0 && seg[1].second == 0? seg[1].first: -1) << ' ';
    }
    cout << '\n';
    return 0;
}


#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
struct node {
    int val, mini, maxi, lazy;
};
node seg[4 * maxn];
int mark[maxn];
void push(int index, int left, int right) {
    seg[index].maxi += seg[index].lazy;
    seg[index].mini += seg[index].lazy;
    seg[index].val += (right - left + 1) * seg[index].lazy;
    if (left != right) {
        int mid = (left + right) / 2;
        seg[2 * index].lazy += seg[index].lazy;
        seg[2 * index + 1].lazy += seg[index].lazy;
        push(2 * index, left, mid); push(2 * index + 1, mid + 1, right);
    }
    seg[index].lazy = 0;
}
void update(int index, int left, int right, int lo, int hi, int val) {
    push(index, left, right);
    if (lo <= left && right <= hi) {
        seg[index].lazy += val;
        push(index, left, right);
        return;
    }
    int mid = (left + right) / 2;
    if (hi <= mid) update(2 * index, left, mid, lo, hi, val);
    else if (lo > mid) update(2 * index + 1, mid + 1, right, lo, hi, val);
    else {
        update(2 * index, left, mid, lo, hi, val); update(2 * index + 1, mid + 1, right, lo, hi, val);
    }
    seg[index].maxi = max(seg[2 * index].maxi, seg[2 * index + 1].maxi);
    seg[index].mini = min(seg[2 * index].mini, seg[2 * index + 1].mini);
    seg[index].val = seg[2 * index].val + seg[2 * index + 1].val;
}
int query(int index, int left, int right, int pos) {
    push(index, left, right);
    if (left == right) {
        return seg[index].val == 0 && seg[1].mini == 0? seg[1].maxi: -1;
    }
    int mid = (left + right) / 2;
    if (pos <= mid) return query(2 * index, left, mid, pos);
    return query(2 * index + 1, mid + 1, right, pos);
}
int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    int n; cin >> n;
    string s; cin >> s;
    int cursor = 0;
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cursor;
        else if (s[i] == 'L') cursor = max(0, cursor - 1);
        else if (s[i] == '(' && mark[cursor] != 1) {
            update(1, 0, maxn, cursor, maxn, 1 - mark[cursor]);
            mark[cursor] = 1;
        } else if (s[i] == ')' && mark[cursor] != -1) {
            update(1, 0, maxn, cursor, maxn, -1 - mark[cursor]);
            mark[cursor] = -1;
        } else if (isalpha(s[i]) && mark[cursor]) {
            update(1, 0, maxn, cursor, maxn, -mark[cursor]);
            mark[cursor] = 0;
        }
        cout << query(1, 0, maxn, maxn) << ' ';
    }
    cout << '\n';
    return 0;
}


#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
typedef pair<int, int> pii;
typedef pair<pii, pii> ppi;
ppi seg[4 * maxn];
int mark[maxn];
void push(int index, int left, int right) {
    seg[index].first.first += seg[index].second.second;
    seg[index].first.second += seg[index].second.second;
    seg[index].second.first += (right - left + 1) * seg[index].second.second;
    if (left != right) {
        int mid = (left + right) / 2;
        seg[2 * index].second.second += seg[index].second.second;
        seg[2 * index + 1].second.second += seg[index].second.second;
    }
    seg[index].second.second = 0;
}
void update(int index, int left, int right, int lo, int hi, int val) {
    push(index, left, right);
    if (lo > right || hi < left) return;
    if (lo <= left && right <= hi) {
        seg[index].second.second += val;
        push(index, left, right);
        return;
    }
    int mid = (left + right) / 2;
    update(2 * index, left, mid, lo, hi, val); update(2 * index + 1, mid + 1, right, lo, hi, val);
    seg[index].first.first = max(seg[2 * index].first.first, seg[2 * index + 1].first.first);
    seg[index].first.second = min(seg[2 * index].first.second, seg[2 * index + 1].first.second);
    seg[index].second.first = seg[2 * index].second.first + seg[2 * index + 1].second.first;
}
int query(int index, int left, int right, int pos) {
    push(index, left, right);
    if (left == right) {
        return seg[index].second.first == 0 && seg[1].first.second == 0? seg[1].first.first: -1;
    }
    int mid = (left + right) / 2;
    if (pos <= mid) return query(2 * index, left, mid, pos);
    return query(2 * index + 1, mid + 1, right, pos);
}
int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    int n; cin >> n;
    string s; cin >> s;
    int cursor = 0, bound = 0, cur = 0;
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cur;
        else if (s[i] == 'L') --cur;
        bound = max(bound, cur);
    }
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cursor;
        else if (s[i] == 'L') cursor = max(0, cursor - 1);
        else if (s[i] == '(' && mark[cursor] != 1) {
            update(1, 0, bound, cursor, bound, 1 - mark[cursor]);
            mark[cursor] = 1;
        } else if (s[i] == ')' && mark[cursor] != -1) {
            update(1, 0, bound, cursor, bound, -1 - mark[cursor]);
            mark[cursor] = -1;
        } else if (isalpha(s[i]) && mark[cursor]) {
            update(1, 0, bound, cursor, bound, -mark[cursor]);
            mark[cursor] = 0;
        }
        cout << seg[1].first.first << '\n';
        //cout << query(1, 0, bound, bound) << ' ';
    }
    cout << '\n';
    return 0;
}


#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
struct node {
    int val, mini, maxi, lazy;
};
node seg[4 * maxn];
int mark[maxn];
void push(int index, int left, int right) {
    seg[index].maxi += seg[index].lazy;
    seg[index].mini += seg[index].lazy;
    seg[index].val += (right - left + 1) * seg[index].lazy;
    if (left != right) {
        int mid = (left + right) / 2;
        seg[2 * index].lazy += seg[index].lazy;
        seg[2 * index + 1].lazy += seg[index].lazy;
        push(2 * index, left, mid); push(2 * index + 1, mid + 1, right);
    }
    seg[index].lazy = 0;
}
void update(int index, int left, int right, int lo, int hi, int val) {
    push(index, left, right);
    if (lo <= left && right <= hi) {
        seg[index].lazy += val;
        push(index, left, right);
        return;
    }
    int mid = (left + right) / 2;
    if (hi <= mid) update(2 * index, left, mid, lo, hi, val);
    else if (lo > mid) update(2 * index + 1, mid + 1, right, lo, hi, val);
    else {
        update(2 * index, left, mid, lo, hi, val); update(2 * index + 1, mid + 1, right, lo, hi, val);
    }
    seg[index].maxi = max(seg[2 * index].maxi, seg[2 * index + 1].maxi);
    seg[index].mini = min(seg[2 * index].mini, seg[2 * index + 1].mini);
    seg[index].val = seg[2 * index].val + seg[2 * index + 1].val;
}
int query(int index, int left, int right, int pos) {
    push(index, left, right);
    if (left == right) {
        return seg[index].val == 0 && seg[1].mini == 0? seg[1].maxi: -1;
    }
    int mid = (left + right) / 2;
    if (pos <= mid) return query(2 * index, left, mid, pos);
    return query(2 * index + 1, mid + 1, right, pos);
}
int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    int n; cin >> n;
    string s; cin >> s;
    int cursor = 0, bound = 0, cur = 0;
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cur;
        else if (s[i] == 'L') --cur;
        bound = max(bound, cur);
    }
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] == 'R') ++cursor;
        else if (s[i] == 'L') cursor = max(0, cursor - 1);
        else if (s[i] == '(' && mark[cursor] != 1) {
            update(1, 0, bound, cursor, bound, 1 - mark[cursor]);
            mark[cursor] = 1;
        } else if (s[i] == ')' && mark[cursor] != -1) {
            update(1, 0, bound, cursor, bound, -1 - mark[cursor]);
            mark[cursor] = -1;
        } else if (isalpha(s[i]) && mark[cursor]) {
            update(1, 0, bound, cursor, bound, -mark[cursor]);
            mark[cursor] = 0;
        }
        cout << query(1, 0, bound, bound) << ' ';
    }
    cout << '\n';
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[ver * 2].mod += t[ver].mod;
    t[ver * 2 + 1].mod += t[ver].mod;
    int ll = l, lr = l + (r - l) / 2;
    int rl = lr + 1, rr = r;
    t[ver * 2].minVal += (t[ver].mod);
    t[ver * 2 + 1].minVal += (t[ver].mod);

    t[ver * 2].maxVal += (t[ver].mod);
    t[ver * 2 + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    int mid = l + (r - l) / 2;
    push(ver, l, r);
    update(ver * 2, l, mid, nl, nr, val);
    update(ver * 2 + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[ver * 2].minVal, t[ver * 2 + 1].minVal);
    t[ver].maxVal = max(t[ver * 2].maxVal, t[ver * 2 + 1].maxVal);
}

int main() {
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << endl;
        } else {
            cout << -1 << endl;
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt, ll, rr, lr, rl, mid;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[(ver << 1)].mod += t[ver].mod;
    t[(ver << 1) + 1].mod += t[ver].mod;
    ll = l, lr = l + (r - l) / 2;
    rl = lr + 1, rr = r;
    t[(ver << 1)].minVal += (t[ver].mod);
    t[(ver << 1) + 1].minVal += (t[ver].mod);

    t[(ver << 1)].maxVal += (t[ver].mod);
    t[(ver << 1) + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    mid = l + (r - l) / 2;
    push(ver, l, r);
    update((ver << 1), l, mid, nl, nr, val);
    update((ver << 1) + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[(ver << 1)].minVal, t[(ver << 1) + 1].minVal);
    t[ver].maxVal = max(t[(ver << 1)].maxVal, t[(ver << 1) + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << '\n';
        } else {
            cout << -1 << '\n';
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt, ll, rr, lr, rl, mid;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[(ver << 1)].mod += t[ver].mod;
    t[(ver << 1) + 1].mod += t[ver].mod;
    ll = l, lr = l + (r - l) / 2;
    rl = lr + 1, rr = r;
    t[(ver << 1)].minVal += (t[ver].mod);
    t[(ver << 1) + 1].minVal += (t[ver].mod);

    t[(ver << 1)].maxVal += (t[ver].mod);
    t[(ver << 1) + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    mid = l + (r - l) / 2;
    push(ver, l, r);
    update((ver << 1), l, mid, nl, nr, val);
    update((ver << 1) + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[(ver << 1)].minVal, t[(ver << 1) + 1].minVal);
    t[ver].maxVal = max(t[(ver << 1)].maxVal, t[(ver << 1) + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (tt == 'R') {
            pos++;
        } else {
            if (tt == 'L') {
                pos--;
            } else {
                if (arr[pos] != tt) {
                    if (tt == '(') {
                        cnt++;
                        if (arr[pos] == ')') {
                            cnt++;
                            update(1, 1, n, pos, n, 2);
                        } else {
                            update(1, 1, n, pos, n, 1);
                        }
                        arr[pos] = tt;
                    }
                    if (tt == ')') {
                        cnt--;
                        if (arr[pos] == '(') {
                            cnt--;
                            update(1, 1, n, pos, n, -2);
                        } else {
                            update(1, 1, n, pos, n, -1);
                        }
                        arr[pos] = tt;
                    }
                    if (tt >= 'a' && tt <= 'z') {
                        if (arr[pos] == '(') {
                            cnt--;
                            update(1, 1, n, pos, n, -1);
                        }
                        if (arr[pos] == ')') {
                            cnt++;
                            update(1, 1, n, pos, n, 1);
                        }
                        arr[pos] = tt;
                    }
                }
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << '\n';
        } else {
            cout << -1 << '\n';
        }
    }

}


#include <bits/stdc++.h>

#pragma GCC optimize("-O3")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[ver * 2].mod += t[ver].mod;
    t[ver * 2 + 1].mod += t[ver].mod;
    int ll = l, lr = l + (r - l) / 2;
    int rl = lr + 1, rr = r;
    t[ver * 2].minVal += (t[ver].mod);
    t[ver * 2 + 1].minVal += (t[ver].mod);

    t[ver * 2].maxVal += (t[ver].mod);
    t[ver * 2 + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    int mid = l + (r - l) / 2;
    push(ver, l, r);
    update(ver * 2, l, mid, nl, nr, val);
    update(ver * 2 + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[ver * 2].minVal, t[ver * 2 + 1].minVal);
    t[ver].maxVal = max(t[ver * 2].maxVal, t[ver * 2 + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << endl;
        } else {
            cout << -1 << endl;
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4001000];

int n, pos, cnt, ll, rr, lr, rl, mid;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[(ver << 1)].mod += t[ver].mod;
    t[(ver << 1) + 1].mod += t[ver].mod;
    ll = l, lr = l + (r - l) / 2;
    rl = lr + 1, rr = r;
    t[(ver << 1)].minVal += (t[ver].mod);
    t[(ver << 1) + 1].minVal += (t[ver].mod);

    t[(ver << 1)].maxVal += (t[ver].mod);
    t[(ver << 1) + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    mid = l + (r - l) / 2;
    push(ver, l, r);
    update((ver << 1), l, mid, nl, nr, val);
    update((ver << 1) + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[(ver << 1)].minVal, t[(ver << 1) + 1].minVal);
    t[ver].maxVal = max(t[(ver << 1)].maxVal, t[(ver << 1) + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << ' ';
        } else {
            cout << -1 << ' ';
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[ver * 2].mod += t[ver].mod;
    t[ver * 2 + 1].mod += t[ver].mod;
    int ll = l, lr = l + (r - l) / 2;
    int rl = lr + 1, rr = r;
    t[ver * 2].minVal += (t[ver].mod);
    t[ver * 2 + 1].minVal += (t[ver].mod);

    t[ver * 2].maxVal += (t[ver].mod);
    t[ver * 2 + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    int mid = l + (r - l) / 2;
    push(ver, l, r);
    update(ver * 2, l, mid, nl, nr, val);
    update(ver * 2 + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[ver * 2].minVal, t[ver * 2 + 1].minVal);
    t[ver].maxVal = max(t[ver * 2].maxVal, t[ver * 2 + 1].maxVal);
}

int main() {
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (tt == arr[pos]) {
            continue;
        }
        if (tt == '(') {
            cnt++;
            if (arr[pos] == ')') {
                cnt++;
                update(1, 1, n, pos, n, 2);
            } else {
                update(1, 1, n, pos, n, 1);
            }
            arr[pos] = tt;
        }
        if (tt == ')') {
            cnt--;
            if (arr[pos] == '(') {
                cnt--;
                update(1, 1, n, pos, n, -2);
            } else {
                update(1, 1, n, pos, n, -1);
            }
            arr[pos] = tt;
        }
        if (tt == 'R') {
            pos++;
        }
        if (tt == 'L') {
            pos--;
        }
        if (tt >= 'a' && tt <= 'z') {
            if (arr[pos] == '(') {
                cnt--;
                update(1, 1, n, pos, n, -1);
            }
            if (arr[pos] == ')') {
                cnt++;
                update(1, 1, n, pos, n, 1);
            }
            arr[pos] = tt;
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << endl;
        } else {
            cout << -1 << endl;
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4001000];

int n, pos, cnt, ll, rr, lr, rl, mid;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[(ver << 1)].mod += t[ver].mod;
    t[(ver << 1) + 1].mod += t[ver].mod;
    ll = l, lr = l + (r - l) / 2;
    rl = lr + 1, rr = r;
    t[(ver << 1)].minVal += (t[ver].mod);
    t[(ver << 1) + 1].minVal += (t[ver].mod);

    t[(ver << 1)].maxVal += (t[ver].mod);
    t[(ver << 1) + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    mid = l + (r - l) / 2;
    push(ver, l, r);
    update((ver << 1), l, mid, nl, nr, val);
    update((ver << 1) + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[(ver << 1)].minVal, t[(ver << 1) + 1].minVal);
    t[ver].maxVal = max(t[(ver << 1)].maxVal, t[(ver << 1) + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
                pos = max(pos, 1);
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << ' ';
        } else {
            cout << -1 << ' ';
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[ver * 2].mod += t[ver].mod;
    t[ver * 2 + 1].mod += t[ver].mod;
    int ll = l, lr = l + (r - l) / 2;
    int rl = lr + 1, rr = r;
    t[ver * 2].minVal += (t[ver].mod);
    t[ver * 2 + 1].minVal += (t[ver].mod);

    t[ver * 2].maxVal += (t[ver].mod);
    t[ver * 2 + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    int mid = l + (r - l) / 2;
    push(ver, l, r);
    update(ver * 2, l, mid, nl, nr, val);
    update(ver * 2 + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[ver * 2].minVal, t[ver * 2 + 1].minVal);
    t[ver].maxVal = max(t[ver * 2].maxVal, t[ver * 2 + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << endl;
        } else {
            cout << -1 << endl;
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt, ll, rr, lr, rl, mid;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[(ver << 1)].mod += t[ver].mod;
    t[(ver << 1)].mod += t[ver].mod;
    ll = l, lr = l + ((r - l) >> 1);
    rl = lr + 1, rr = r;
    t[(ver << 1)].minVal += (t[ver].mod);
    t[(ver << 1) + 1].minVal += (t[ver].mod);

    t[(ver << 1)].maxVal += (t[ver].mod);
    t[(ver << 1) + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    mid = l + ((r - l) >> 1);
    push(ver, l, r);
    update((ver << 1), l, mid, nl, nr, val);
    update((ver << 1) + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[(ver << 1)].minVal, t[(ver << 1) + 1].minVal);
    t[ver].maxVal = max(t[(ver << 1)].maxVal, t[(ver << 1) + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << endl;
        } else {
            cout << -1 << endl;
        }
    }

}


#include <bits/stdc++.h>

using namespace std;

struct SegmentTree {
    int sum, minVal, maxVal, mod;
};

SegmentTree t[4000000];

int n, pos, cnt, ll, rr, lr, rl, mid;
char arr[1001000];
char tt;

void push(int ver, int l, int r) {
    t[(ver << 1)].mod += t[ver].mod;
    t[(ver << 1) + 1].mod += t[ver].mod;
    ll = l, lr = l + (r - l) / 2;
    rl = lr + 1, rr = r;
    t[(ver << 1)].minVal += (t[ver].mod);
    t[(ver << 1) + 1].minVal += (t[ver].mod);

    t[(ver << 1)].maxVal += (t[ver].mod);
    t[(ver << 1) + 1].maxVal += (t[ver].mod);
    t[ver].mod = 0;
}

void update(int ver, int l, int r, int nl, int nr, int val) {
    if (l > nr || r < nl) {
        return;
    }
    if (l >= nl && r <= nr) {
        t[ver].mod += val;
        t[ver].maxVal += val;
        t[ver].minVal += val;
        return;
    }
    mid = l + (r - l) / 2;
    push(ver, l, r);
    update((ver << 1), l, mid, nl, nr, val);
    update((ver << 1) + 1, mid + 1, r, nl, nr, val);
    t[ver].minVal = min(t[(ver << 1)].minVal, t[(ver << 1) + 1].minVal);
    t[ver].maxVal = max(t[(ver << 1)].maxVal, t[(ver << 1) + 1].maxVal);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    pos = 1;
    for (int i = 1; i <= n; i++) {
        cin >> tt;
        if (arr[pos] != tt) {
            if (tt == '(') {
                cnt++;
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 2);
                } else {
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
            if (tt == ')') {
                cnt--;
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -2);
                } else {
                    update(1, 1, n, pos, n, -1);
                }
                arr[pos] = tt;
            }
            if (tt == 'R') {
                pos++;
            }
            if (tt == 'L') {
                pos--;
            }
            if (tt >= 'a' && tt <= 'z') {
                if (arr[pos] == '(') {
                    cnt--;
                    update(1, 1, n, pos, n, -1);
                }
                if (arr[pos] == ')') {
                    cnt++;
                    update(1, 1, n, pos, n, 1);
                }
                arr[pos] = tt;
            }
        }
        if (cnt == 0 && t[1].minVal >= 0) {
            cout << t[1].maxVal << endl;
        } else {
            cout << -1 << endl;
        }
    }

}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 10;

int n, P, L, R;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 0;

	for(int i = 0; i < n; ++i){

		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;

		L = min(L, P);
		R = max(R, P);
	}

	R -= L;
	P = -L;
	L = 0;

	L++;
	R++;
	P++;

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;
		else{
			if(c[P] == ')')
				upd(P, R, +1);

			else if(c[P] == '(')
				upd(P, R, -1);

			if(s[i] == '(')
				upd(P, R, +1);

			else if(s[i] == ')')
				upd(P, R, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, R) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 500;

int n, P, L, R;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 1;

	for(int i = 0; i < n; ++i){

		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;

		R = max(R, P);
	}

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;
		else{
			if(c[P] == ')')
				upd(P, R, +1);

			else if(c[P] == '(')
				upd(P, R, -1);

			if(s[i] == '(')
				upd(P, R, +1);

			else if(s[i] == ')')
				upd(P, R, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, R) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e18;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 123;

ll n, P, L, R;
string s;
char c[MAXN];
ll tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

void push(ll v, ll tl, ll tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

void upd(ll l, ll r, ll x, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

ll get_min(ll l, ll r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

ll get_max(ll l, ll r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 0;

	for(int i = 0; i < n; ++i){

		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;

		L = min(L, P);
		R = max(R, P);
	}

	R -= L;
	P = -L;
	L = 0;

	L++;
	R++;
	P++;

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;
		else{
			if(c[P] == ')')
				upd(P, R, +1);

			else if(c[P] == '(')
				upd(P, R, -1);

			if(s[i] == '(')
				upd(P, R, +1);

			else if(s[i] == ')')
				upd(P, R, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, R) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 1e5;

int n, P, L, R;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 0;

	for(int i = 0; i < n; ++i){

		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P = max(1, P - 1);

		L = min(L, P);
		R = max(R, P);
	}

	R -= L;
	P = -L;
	L = 0;

	L++;
	R++;
	P++;

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P = max(1, P - 1);
		else{
			if(c[P] == ')')
				upd(P, R, +1);

			else if(c[P] == '(')
				upd(P, R, -1);

			if(s[i] == '(')
				upd(P, R, +1);

			else if(s[i] == ')')
				upd(P, R, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, R) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 10;

int n, P, L, R;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 1;

	for(int i = 0; i < n; ++i){

		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;

		R = max(R, P);
	}

	P = 1;

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;
		else{
			if(c[P] == ')')
				upd(P, R, +1);

			else if(c[P] == '(')
				upd(P, R, -1);

			if(s[i] == '(')
				upd(P, R, +1);

			else if(s[i] == ')')
				upd(P, R, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, R) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 1e5;

int n, P, L, R;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 0;

	for(int i = 0; i < n; ++i){

		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;

		L = min(L, P);
		R = max(R, P);
	}

	R -= L;
	P = -L;
	L = 0;

	L++;
	R++;
	P++;

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;
		else{
			if(c[P] == ')')
				upd(P, R, +1);

			else if(c[P] == '(')
				upd(P, R, -1);

			if(s[i] == '(')
				upd(P, R, +1);

			else if(s[i] == ')')
				upd(P, R, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, R) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
	freopen(NAME".in", "r", stdin);
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 1e5;

int n, P, L, R;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = R){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 1;
	R = n;

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P = max(1, P - 1);
		else{
			if(c[P] == ')')
				upd(P, R, +1);

			else if(c[P] == '(')
				upd(P, R, -1);

			if(s[i] == '(')
				upd(P, R, +1);

			else if(s[i] == ')')
				upd(P, R, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, R) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 500;

int n, P;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = MAXN){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = MAXN){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = MAXN){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 1;

	for(int i = 0; i < n; ++i){
 		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;
		else{
			if(c[P] == ')')
				upd(P, MAXN, +1);

			else if(c[P] == '(')
				upd(P, MAXN, -1);

			if(s[i] == '(')
				upd(P, MAXN, +1);

			else if(s[i] == ')')
				upd(P, MAXN, -1);

			c[P] = s[i];
		}

		if(get_min(1, MAXN) >= 0 && get_min(MAXN, MAXN) == 0){
			cout << get_max(1, MAXN) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define fr first
#define sc second
#define all(x) x.begin(), x.end()
#define skip continue
#define NAME "code"

using namespace std;

typedef long long ll;
typedef long double ld;

void faster(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const ll INF = 1e9;
const ll MOD = 1e9 + 7;
const ll MAXN = 1e6 + 123;

int n, P, L, R;
string s;
char c[MAXN];
int tmn[MAXN * 4], tmx[MAXN * 4], z[MAXN * 4];

inline void push(int v, int tl, int tr){
	tmx[v] += z[v];
	tmn[v] += z[v];

	if(tl != tr){
		z[v + v] += z[v];
		z[v + v + 1] += z[v];
	}

	z[v] = 0;
}

inline void upd(int l, int r, int x, int v = 1, int tl = 1, int tr = MAXN){
	push(v, tl, tr);

	if(r < tl || tr < l) return;
	if(l <= tl && tr <= r){
		z[v] += x;
		push(v, tl, tr);
		return;
	}

	int tm = (tl + tr) >> 1;

	upd(l, r, x, v + v, tl, tm);
	upd(l, r, x, v + v + 1, tm + 1, tr);

	tmn[v] = min(tmn[v + v], tmn[v + v + 1]);
	tmx[v] = max(tmx[v + v], tmx[v + v + 1]);
}

inline int get_min(int l, int r, int v = 1, int tl = 1, int tr = MAXN){
	push(v, tl, tr);

	if(r < tl || tr < l) return INF;
	if(l <= tl && tr <= r) return tmn[v];

	int tm = (tl + tr) >> 1;

	return min(get_min(l, r, v + v, tl, tm), get_min(l, r, v + v + 1, tm + 1, tr));
}

inline int get_max(int l, int r, int v = 1, int tl = 1, int tr = MAXN){
	push(v, tl, tr);

	if(r < tl || tr < l) return -INF;
	if(l <= tl && tr <= r) return tmx[v];

	int tm = (tl + tr) >> 1;

	return max(get_max(l, r, v + v, tl, tm), get_max(l, r, v + v + 1, tm + 1, tr));
}

int main(){

	faster();

	cin >> n;
	cin >> s;

	P = 1;

	for(int i = 0; i < n; ++i){
		if(s[i] == 'R')
			P++;
		else if(s[i] == 'L')
			P--;
		else{
			if(c[P] == ')')
				upd(P, MAXN, +1);

			else if(c[P] == '(')
				upd(P, MAXN, -1);

			if(s[i] == '(')
				upd(P, MAXN, +1);

			else if(s[i] == ')')
				upd(P, MAXN, -1);

			c[P] = s[i];
		}

		if(get_min(1, R) >= 0 && get_min(R, R) == 0){
			cout << get_max(1, MAXN) << ' ';
		}
		else{
			cout << -1 << ' ';
		}

	}

	return 0;
}


#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = Monoid(*) (Monoid, Monoid);
    using FunctionMO = Monoid(*) (Monoid, OperatorMonoid, int); // 3rd param = length;
    using FunctionO = OperatorMonoid(*) (OperatorMonoid, OperatorMonoid);

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM, const Monoid initVal)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, initVal); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    inline void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    inline Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

pair<int, int> F(pair<int, int> a, pair<int, int> b) { return {min(a.first, b.first), max(a.second, b.second)}; };
pair<int, int> G(pair<int, int> a, int b, int len) {return {a.first + b, a.second + b};}
int H(int a, int b) {return a + b;}
pair<int, int> id = {1e9, -1e9}, zero = {0, 0};

int v[1000000];
vector<int> ans;

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<pair<int, int>, int> lst(n, F, G, H, id, 0, zero);
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            int a = c == '(' ? 1 : c == ')' ? -1 : 0;
            if (a != v[curr]) {
                lst.update(curr, n, a - v[curr]);
                v[curr] = a;
            }
        }
        auto cq = lst.query(0, n);
        if (cq.first < 0 || lst[n-1].first) ans.emplace_back(-1);
        else ans.emplace_back(cq.second);
    }
    for (int i = 0; i < n; i++) {
        cout << ans[i] << " ";
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = function< Monoid(Monoid, Monoid) >;
    using FunctionMO = function< Monoid(Monoid, OperatorMonoid, int) >; // 3rd param = length;
    using FunctionO = function < OperatorMonoid(OperatorMonoid, OperatorMonoid) >;

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

int F(int a, int b) { return min(a, b); };
int E(int a, int b) { return max(a, b); };
int G(int a, int b, int len) {return a + b;}
int H(int a, int b) {return a + b;}

int v[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<int> lst(n, F, G, H, 1e9, 0), xlst(n, E, G, H, -1e9, 0);
    for (int i = 0; i < n; i++) lst.set(i, 0), xlst.set(i, 0);
    lst.build(); xlst.build();
    string s; cin >> s;
    int curr = 0;
    vector<int> ans;
    for (auto &c: s) {
        if (c == '(') {
            if (1 - v[curr]) {
                lst.update(curr, n, 1 - v[curr]);
                xlst.update(curr, n, 1 - v[curr]);
            }
            v[curr] = 1;
        } else if (c == ')') {
            if (-1 - v[curr]) {
                lst.update(curr, n, -1 - v[curr]);
                xlst.update(curr, n, -1 - v[curr]);
            }
            v[curr] = -1;
        } else if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            curr--;
        }
        int mini = lst.query(0, n);
        if (mini < 0 || lst[n-1]) ans.emplace_back(-1);
        else ans.emplace_back(xlst.query(0, n));
    }
    for (int i = 0; i < n; i++) {
        if (i) cout << " ";
        cout << ans[i];
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = Monoid(*) (Monoid, Monoid);
    using FunctionMO = Monoid(*) (Monoid, OperatorMonoid, int); // 3rd param = length;
    using FunctionO = OperatorMonoid(*) (OperatorMonoid, OperatorMonoid);

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM, const Monoid initVal)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, initVal); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    inline void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

pair<int, int> F(pair<int, int> a, pair<int, int> b) { return {min(a.first, b.first), max(a.second, b.second)}; };
pair<int, int> G(pair<int, int> a, int b, int len) {return {a.first + b, a.second + b};}
int H(int a, int b) {return a + b;}
pair<int, int> id = {1e9, -1e9}, zero = {0, 0};

int v[1000000];
vector<int> ans;

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<pair<int, int>, int> lst(n, F, G, H, id, 0, zero);
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            int a = c == '(' ? 1 : c == ')' ? -1 : 0;
            lst.update(curr, n, a - v[curr]);
            v[curr] = a;
        }
        auto cq = lst.query(0, n);
        if (cq.first < 0 || lst[n-1].first) ans.emplace_back(-1);
        else ans.emplace_back(cq.second);
    }
    for (int i = 0; i < n; i++) {
        cout << ans[i] << " ";
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid, class FunctionM, class FunctionMO, class FunctionO>
struct LazySegmentTree {
    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM, const Monoid initVal)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, initVal); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    inline void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    inline Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

auto F = [&](pair<int, int> a, pair<int, int> b) { return make_pair(min(a.first, b.first), max(a.second, b.second)); };
auto G = [&](pair<int, int> a, int b, int len) { return make_pair(a.first + b, a.second + b); };
auto H = [&](int a, int b) {return a + b;};
pair<int, int> id = {1e9, -1e9}, zero = {0, 0};

int v[1000000];
int ans[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<pair<int, int>, int, decltype(F), decltype(G), decltype(H)> lst(n, F, G, H, id, 0, zero);
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            int a = c == '(' ? 1 : c == ')' ? -1 : 0;
            if (a != v[curr]) {
                lst.update(curr, n, a - v[curr]);
                v[curr] = a;
            }
        }
        auto cq = lst.query(0, n);
        if (cq.first < 0 || lst[n-1].first) ans[j++] = -1;
        else ans[j++] = cq.second;
    }
    for (int i = 0; i < n; i++) {
        cout << ans[i] << " ";
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = Monoid(*) (Monoid, Monoid);
    using FunctionMO = Monoid(*) (Monoid, OperatorMonoid, int); // 3rd param = length;
    using FunctionO = OperatorMonoid(*) (OperatorMonoid, OperatorMonoid);

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

int F(int a, int b) { return min(a, b); };
int E(int a, int b) { return max(a, b); };
int G(int a, int b, int len) {return a + b;}
int H(int a, int b) {return a + b;}

int v[1000000];
int ans[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<int> lst(n, F, G, H, 1e9, 0), xlst(n, E, G, H, -1e9, 0);
    for (int i = 0; i < n; i++) lst.set(i, 0), xlst.set(i, 0);
    lst.build(); xlst.build();
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == '(') {
            if (1 - v[curr]) {
                lst.update(curr, n, 1 - v[curr]);
                xlst.update(curr, n, 1 - v[curr]);
            }
            v[curr] = 1;
        } else if (c == ')') {
            if (-1 - v[curr]) {
                lst.update(curr, n, -1 - v[curr]);
                xlst.update(curr, n, -1 - v[curr]);
            }
            v[curr] = -1;
        } else if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            if (v[curr]) {
                lst.update(curr, n, -v[curr]);
                xlst.update(curr, n, -v[curr]);
            }
            v[curr] = 0;
        }
        int mini = lst.query(0, n);
        if (mini < 0 || lst[n-1]) ans[j++] = -1;
        else ans[j++] = xlst.query(0, n);
    }
    for (int i = 0; i < n; i++) {
        if (i) cout << " ";
        cout << ans[i];
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = Monoid(*) (Monoid, Monoid);
    using FunctionMO = Monoid(*) (Monoid, OperatorMonoid, int); // 3rd param = length;
    using FunctionO = OperatorMonoid(*) (OperatorMonoid, OperatorMonoid);

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    inline void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

int F(int a, int b) { return min(a, b); };
int E(int a, int b) { return max(a, b); };
int G(int a, int b, int len) {return a + b;}
int H(int a, int b) {return a + b;}

int v[1000000];
int ans[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<int> lst(n, F, G, H, 1e9, 0), xlst(n, E, G, H, -1e9, 0);
    for (int i = 0; i < n; i++) lst.set(i, 0), xlst.set(i, 0);
    lst.build(); xlst.build();
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == '(') {
            if (1 - v[curr]) {
                lst.update(curr, n, 1 - v[curr]);
                xlst.update(curr, n, 1 - v[curr]);
            }
            v[curr] = 1;
        } else if (c == ')') {
            if (-1 - v[curr]) {
                lst.update(curr, n, -1 - v[curr]);
                xlst.update(curr, n, -1 - v[curr]);
            }
            v[curr] = -1;
        } else if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            if (v[curr]) {
                lst.update(curr, n, -v[curr]);
                xlst.update(curr, n, -v[curr]);
            }
            v[curr] = 0;
        }
        int mini = lst.query(0, n);
        if (mini < 0 || lst[n-1]) ans[j++] = -1;
        else ans[j++] = xlst.query(0, n);
    }
    for (int i = 0; i < n; i++) {
        if (i) cout << " ";
        cout << ans[i];
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = Monoid(*) (Monoid, Monoid);
    using FunctionMO = Monoid(*) (Monoid, OperatorMonoid, int); // 3rd param = length;
    using FunctionO = OperatorMonoid(*) (OperatorMonoid, OperatorMonoid);

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM, const Monoid initVal)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, initVal); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    inline void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

pair<int, int> F(pair<int, int> a, pair<int, int> b) { return {min(a.first, b.first), max(a.second, b.second)}; };
pair<int, int> G(pair<int, int> a, int b, int len) {return {a.first + b, a.second + b};}
int H(int a, int b) {return a + b;}
pair<int, int> id = {1e9, -1e9}, zero = {0, 0};

int v[1000000];
int ans[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<pair<int, int>, int> lst(n, F, G, H, id, 0, zero);
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == '(') {
            if (1 - v[curr]) {
                lst.update(curr, n, 1 - v[curr]);
            }
            v[curr] = 1;
        } else if (c == ')') {
            if (-1 - v[curr]) {
                lst.update(curr, n, -1 - v[curr]);
            }
            v[curr] = -1;
        } else if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            if (v[curr]) {
                lst.update(curr, n, -v[curr]);
            }
            v[curr] = 0;
        }
        auto cq = lst.query(0, n);
        if (cq.first < 0 || lst[n-1].first) ans[j++] = -1;
        else ans[j++] = cq.second;
    }
    for (int i = 0; i < n; i++) {
        if (i) cout << " ";
        cout << ans[i];
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = function< Monoid(Monoid, Monoid) >;
    using FunctionMO = function< Monoid(Monoid, OperatorMonoid, int) >; // 3rd param = length;
    using FunctionO = function < OperatorMonoid(OperatorMonoid, OperatorMonoid) >;

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

int F(int a, int b) { return min(a, b); };
int E(int a, int b) { return max(a, b); };
int G(int a, int b, int len) {return a + b;}
int H(int a, int b) {return a + b;}

int v[1000000];
int ans[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<int> lst(n, F, G, H, 1e9, 0), xlst(n, E, G, H, -1e9, 0);
    for (int i = 0; i < n; i++) lst.set(i, 0), xlst.set(i, 0);
    lst.build(); xlst.build();
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == '(') {
            if (1 - v[curr]) {
                lst.update(curr, n, 1 - v[curr]);
                xlst.update(curr, n, 1 - v[curr]);
            }
            v[curr] = 1;
        } else if (c == ')') {
            if (-1 - v[curr]) {
                lst.update(curr, n, -1 - v[curr]);
                xlst.update(curr, n, -1 - v[curr]);
            }
            v[curr] = -1;
        } else if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            if (v[curr]) {
                lst.update(curr, n, -v[curr]);
                xlst.update(curr, n, -v[curr]);
            }
            v[curr] = 0;
        }
        int mini = lst.query(0, n);
        if (mini < 0 || lst[n-1]) ans[j++] = -1;
        else ans[j++] = xlst.query(0, n);
    }
    for (int i = 0; i < n; i++) {
        if (i) cout << " ";
        cout << ans[i];
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = Monoid(*) (Monoid, Monoid);
    using FunctionMO = Monoid(*) (Monoid, OperatorMonoid, int); // 3rd param = length;
    using FunctionO = OperatorMonoid(*) (OperatorMonoid, OperatorMonoid);

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM, const Monoid initVal)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, initVal); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    inline void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

pair<int, int> F(pair<int, int> a, pair<int, int> b) { return {min(a.first, b.first), max(a.second, b.second)}; };
pair<int, int> G(pair<int, int> a, int b, int len) {return {a.first + b, a.second + b};}
int H(int a, int b) {return a + b;}
pair<int, int> id = {1e9, -1e9}, zero = {0, 0};

int v[1000000];
int ans[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<pair<int, int>, int> lst(n, F, G, H, id, 0, zero);
    string s; cin >> s;
    int curr = 0; int j = 0;
    for (auto &c: s) {
        if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            if (curr) curr--;
        } else {
            int a = c == '(' ? 1 : c == ')' ? -1 : 0;
            lst.update(curr, n, a - v[curr]);
            v[curr] = a;
        }
        auto cq = lst.query(0, n);
        if (cq.first < 0 || lst[n-1].first) ans[j++] = -1;
        else ans[j++] = cq.second;
    }
    for (int i = 0; i < n; i++) {
        cout << ans[i] << " ";
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

template<class Monoid, class OperatorMonoid = Monoid>
struct LazySegmentTree {
    using FunctionM = function< Monoid(Monoid, Monoid) >;
    using FunctionMO = function< Monoid(Monoid, OperatorMonoid, int) >; // 3rd param = length;
    using FunctionO = function < OperatorMonoid(OperatorMonoid, OperatorMonoid) >;

    int N; vector<Monoid> segment; vector<OperatorMonoid> lazy;
    const FunctionM FuncM; const FunctionMO FuncMO; const FunctionO FuncO;
    const Monoid idM; const OperatorMonoid idOM;

    LazySegmentTree(int n, const FunctionM FuncM, const FunctionMO FuncMO, const FunctionO FuncO,
        const Monoid idM, const OperatorMonoid idOM)
    : FuncM(FuncM), FuncMO(FuncMO), FuncO(FuncO), idM(idM), idOM(idOM) {
        N = 1;
        while (N < n) N <<= 1;
        segment.assign(2 * N, idM); lazy.assign(2 * N, idOM);
    }

    void set(int num, Monoid x) {
        segment[N + num] = x;
    }
    void build() {
        for (int k = N - 1; k > 0; k--) {
            segment[k] = FuncM(segment[2*k], segment[2*k+1]);
        }
    }

    void propagate(int k, int len){
        if (lazy[k] != idOM) {
            if (k < N) {
                lazy[2*k] = FuncO(lazy[2*k], lazy[k]);
                lazy[2*k+1] = FuncO(lazy[2*k+1], lazy[k]);
            }
            segment[k] = FuncMO(segment[k], lazy[k], len);
            lazy[k] = idOM;
        }
    }

    // update:[a, b)
    Monoid update(int a, int b, const OperatorMonoid x) {
        return update(a, b, x, 1, 0, N);
    }
    Monoid update(int a, int b, const OperatorMonoid x, int k, int l, int r){
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return segment[k];
        } else if (a <= l && r <= b) {
            lazy[k] = FuncO(lazy[k], x);
            propagate(k, r-l);
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return segment[k] = FuncM(update(a, b, x, 2*k, l, m), update(a, b, x, 2*k+1, m, r));
        }
    }

    // query:[a, b)
    Monoid query(int a, int b) {
        return query(a, b, 1, 0, N);
    }
    Monoid query(int a, int b, int k, int l, int r) {
        propagate(k, r-l);
        if (b <= l || r <= a) {
            return idM;
        } else if (a <= l && r <= b) {
            return segment[k];
        } else {
            int m = (l + r) / 2;
            return FuncM(query(a, b, 2*k, l, m), query(a, b, 2*k+1, m, r));
        }
    }

    // 0-indexed numbering;
    Monoid operator[](const int &k) {
        return query(k, k + 1);
    }
};

int F(int a, int b) { return min(a, b); };
int E(int a, int b) { return max(a, b); };
int G(int a, int b, int len) {return a + b;}
int H(int a, int b) {return a + b;}

int v[1000000];

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    LazySegmentTree<int> lst(n, F, G, H, 1e9, 0), xlst(n, E, G, H, -1e9, 0);
    for (int i = 0; i < n; i++) lst.set(i, 0), xlst.set(i, 0);
    lst.build(); xlst.build();
    string s; cin >> s;
    int curr = 0;
    vector<int> ans;
    for (auto &c: s) {
        if (c == '(') {
            if (1 - v[curr]) {
                lst.update(curr, n, 1 - v[curr]);
                xlst.update(curr, n, 1 - v[curr]);
            }
            v[curr] = 1;
        } else if (c == ')') {
            if (-1 - v[curr]) {
                lst.update(curr, n, -1 - v[curr]);
                xlst.update(curr, n, -1 - v[curr]);
            }
            v[curr] = -1;
        } else if (c == 'R') {
            curr++;
        } else if (c == 'L') {
            curr--;
        } else {
            if (v[curr]) {
                lst.update(curr, n, -v[curr]);
                xlst.update(curr, n, -v[curr]);
            }
            v[curr] = 0;
        }
        int mini = lst.query(0, n);
        if (mini < 0 || lst[n-1]) ans.emplace_back(-1);
        else ans.emplace_back(xlst.query(0, n));
    }
    for (int i = 0; i < n; i++) {
        if (i) cout << " ";
        cout << ans[i];
    }
    cout << "\n";
    return 0;
}