678_F. Lena and Queries

Lena is a programmer. She got a task to solve at work.

There is an empty set of pairs of integers and n queries to process. Each query is one of three types:

  1. Add a pair (a, b) to the set. 
  2. Remove a pair added in the query number i. All queries are numbered with integers from 1 to n. 
  3. For a given integer q find the maximal value x·q + y over all pairs (x, y) from the set. 



Help Lena to process the queries.

Input

The first line of input contains integer n (1 ≤ n ≤ 3·105) — the number of queries.

Each of the next n lines starts with integer t (1 ≤ t ≤ 3) — the type of the query.

A pair of integers a and b ( - 109 ≤ a, b ≤ 109) follows in the query of the first type.

An integer i (1 ≤ i ≤ n) follows in the query of the second type. It is guaranteed that i is less than the number of the query, the query number i has the first type and the pair from the i-th query is not already removed.

An integer q ( - 109 ≤ q ≤ 109) follows in the query of the third type.

Output

For the queries of the third type print on a separate line the desired maximal value of x·q + y.

If there are no pairs in the set print "EMPTY SET".

Example

Input

7
3 1
1 2 3
3 1
1 -1 100
3 1
2 4
3 1


Output

EMPTY SET
5
99
5

Example input:
7
3 1
1 2 3
3 1
1 -1 100
3 1
2 4
3 1


Example output:
EMPTY SET
                                                               5
                                                              99
                                                               5


Tags: data structures
divide and conquer
geometry
Difficulty rating: 2500

Solution:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll inf = 2e18;
const int N = 1400000;
struct line {
  ll a, b;
  line(ll a = 0, ll b = -inf) : a(a), b(b) {}
  ll getValue(ll x) { return a * x + b; }
} L[N];
int qx[N];
void add(int u, int l, int r, line li) {
  int m = l + r >> 1;
  bool lef = L[u].getValue(qx[l]) < li.getValue(qx[l]);
  bool mid = L[u].getValue(qx[m]) < li.getValue(qx[m]);
  if (mid) swap(L[u], li);
  if (r - l == 1) return;
  if (lef == mid)
    add(u + u + 1, m, r, li);
  else
    add(u + u, l, m, li);
}
ll get(int u, int l, int r, int i) {
  ll ret = L[u].getValue(qx[i]);
  int m = l + r >> 1;
  if (r - l == 1) return ret;
  if (i < m) return max(ret, get(u + u, l, m, i));
  return max(ret, get(u + u + 1, m, r, i));
}
int type[N], a[N], b[N], nxt[N], prv[N];
ll ans[N];
void solve(int l, int r) {
  int m = l + r >> 1;
  if (r - l > 1) {
    solve(l, m);
    solve(m, r);
  }
  int qn = 0;
  for (int i = m; i < r; i++) {
    if (type[i] == 3) qx[qn++] = a[i];
  }
  if (!qn) return;
  sort(qx, qx + qn);
  qn = unique(qx, qx + qn) - qx;
  for (int i = 0; i <= (qn << 2); i++) L[i] = line(0, -inf);
  for (int i = l; i < m; i++) {
    if (type[i] == 1 && nxt[i] >= r) add(1, 0, qn, line(a[i], b[i]));
  }
  for (int i = r - 1; i >= m; i--) {
    if (type[i] == 2 && l <= prv[i] && prv[i] < m) {
      add(1, 0, qn, line(a[prv[i]], b[prv[i]]));
    }
    if (type[i] == 3) {
      ans[i] = max(ans[i], get(1, 0, qn, lower_bound(qx, qx + qn, a[i]) - qx));
    }
  }
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  int n;
  cin >> n;
  for (int i = 1; i <= n; i++) nxt[i] = n + 1;
  for (int i = 1; i <= n; i++) {
    cin >> type[i];
    if (type[i] == 1) cin >> a[i] >> b[i];
    if (type[i] == 2) {
      cin >> prv[i];
      nxt[prv[i]] = i;
    }
    if (type[i] == 3) cin >> a[i];
    ans[i] = -inf;
  }
  solve(1, n + 1);
  for (int i = 1; i <= n; i++) {
    if (type[i] == 3) {
      if (ans[i] == -inf)
        cout << "EMPTY SET" << endl;
      else
        cout << ans[i] << endl;
    }
  }
}