#include <bits/stdc++.h>
using namespace std;
enum class Type { Join, Cancel, Query };
struct Query {
  int m_time = 0;
  int m_duration = 0;
  int m_id = 0;
  Type m_type = Type::Join;
};
struct Item {
  Item(int time, int duration, int id, bool query)
      : m_time(time), m_duration(duration), m_id(id), m_query(query) {}
  bool operator<(const Item &rhs) const {
    if (m_time != rhs.m_time) return m_time < rhs.m_time;
    if (m_query != rhs.m_query) return !m_query;
    return m_id < rhs.m_id;
  }
  int m_time = 0;
  int m_duration = 0;
  int m_id = 0;
  bool m_query = false;
  bool m_alive = false;
};
struct Block {
  Block() = default;
  Block(size_t from, size_t to) : m_from(from), m_to(to) {}
  size_t m_from = 0;
  size_t m_to = 0;
  int64_t m_totalDuration = 0;
  int64_t m_pureEndTime = 0;
};
void UpdateBlock(Block &block, const vector<Item> &items) {
  block.m_pureEndTime = 0;
  int64_t duration = block.m_totalDuration;
  for (size_t i = block.m_from; i < block.m_to; ++i) {
    if (!items[i].m_alive) continue;
    assert(duration >= 0);
    const int64_t endTime = items[i].m_time + duration;
    block.m_pureEndTime = max(endTime, block.m_pureEndTime);
    duration -= items[i].m_duration;
  }
  assert(duration == 0);
}
void DoJoin(size_t item, Block &block, vector<Item> &items) {
  assert(item >= block.m_from);
  assert(item < block.m_to);
  assert(!items[item].m_alive);
  assert(!items[item].m_query);
  items[item].m_alive = true;
  block.m_totalDuration += items[item].m_duration;
  UpdateBlock(block, items);
}
void DoCancel(size_t item, Block &block, vector<Item> &items) {
  assert(item >= block.m_from);
  assert(item < block.m_to);
  assert(items[item].m_alive);
  assert(!items[item].m_query);
  items[item].m_alive = false;
  block.m_totalDuration -= items[item].m_duration;
  assert(block.m_totalDuration >= 0);
  UpdateBlock(block, items);
}
int64_t DoQuery(size_t item, const vector<Block> &blocks,
                const vector<Item> &items) {
  assert(item < items.size());
  assert(!items[item].m_alive);
  assert(items[item].m_query);
  int64_t endTime = 0;
  size_t block = 0;
  while (block < blocks.size() && blocks[block].m_to <= item) {
    endTime = max(endTime + blocks[block].m_totalDuration,
                  blocks[block].m_pureEndTime);
    ++block;
  }
  assert(block < blocks.size());
  assert(item >= blocks[block].m_from);
  assert(item < blocks[block].m_to);
  for (size_t i = blocks[block].m_from; i != item; ++i) {
    if (!items[i].m_alive) continue;
    endTime = max<int64_t>(endTime, items[i].m_time) + items[i].m_duration;
  }
  endTime = max<int64_t>(endTime, items[item].m_time);
  return endTime - items[item].m_time;
}
int main() {
  int numQueries;
  char command[4];
  scanf("%d", &numQueries);
  vector<Query> queries(numQueries);
  for (int i = 0; i < numQueries; ++i) {
    auto &query = queries[i];
    scanf("%s", command);
    if (command[0] == '+') {
      query.m_type = Type::Join;
      query.m_id = i;
      scanf("%d%d", &query.m_time, &query.m_duration);
    } else if (command[0] == '-') {
      query.m_type = Type::Cancel;
      int join;
      scanf("%d", &join);
      --join;
      assert(join < i);
      assert(queries[join].m_type == Type::Join);
      query.m_id = queries[join].m_id;
    } else if (command[0] == '?') {
      query.m_type = Type::Query;
      scanf("%d", &query.m_time);
      query.m_id = i;
    } else {
      fprintf(stderr, "Unknown command: %s\n", command);
      assert(false);
    }
  }
  vector<Item> items;
  for (const auto &query : queries) {
    switch (query.m_type) {
      case Type::Join:
      case Type::Query:
        items.emplace_back(query.m_time, query.m_duration, query.m_id,
                           query.m_type == Type::Query);
        break;
      case Type::Cancel:
        break;
    }
  }
  sort(items.begin(), items.end());
  vector<size_t> queryToItem(numQueries);
  for (size_t i = 0; i < items.size(); ++i) {
    const auto id = items[i].m_id;
    assert(id < numQueries);
    queryToItem[id] = i;
  }
  const size_t blockSize =
      min(items.size(), max<size_t>(1, sqrt(items.size())));
  vector<Block> blocks;
  for (size_t from = 0; from < items.size(); from += blockSize) {
    const size_t to = min(from + blockSize, items.size());
    blocks.emplace_back(from, to);
  }
  for (const auto &query : queries) {
    switch (query.m_type) {
      case Type::Join: {
        const auto item = queryToItem[query.m_id];
        const size_t block = item / blockSize;
        DoJoin(item, blocks[block], items);
        break;
      }
      case Type::Cancel: {
        const auto item = queryToItem[query.m_id];
        const size_t block = item / blockSize;
        DoCancel(item, blocks[block], items);
        break;
      }
      case Type::Query: {
        const auto item = queryToItem[query.m_id];
        printf("%lld\n", static_cast<long long>(DoQuery(item, blocks, items)));
        break;
      }
    }
  }
  return 0;
}
