#include <memory>
#include <stdexcept>
#include <iterator>
#include <utility>
#include <initializer_list>

template <typename T, typename Allocator = std::allocator<T>>
class vector {
public:
    using value_type = T;
    
    using allocator_type = Allocator;
    
    using size_type = std::size_t;
    using dfference_type = std::ptrdiff_t;
    
    using reference = value_type&;
    using const_reference = const value_type&;
    
    using pointer = value_type*;
    using const_pointer = const pointer;
    
    using iterator = pointer;
    using const_iterator = const_pointer;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    vector()
    : vector(allocator_type()) {}

    vector(const allocator_type &alloc) noexcept
    : first(nullptr), last(nullptr), reserved_last(nullptr), alloc(alloc) 
    {}

    vector(size_type size, const allocator_type &alloc = allocator_type())
    : vector(alloc)
    {
        resize(size);
    }

    vector(size_type size, const_reference value, const allocator_type &alloc = allocator_type())
    : vector(alloc)
    {
        resize(size, value);
    }

    template <typename InputIterator>
    vector(InputIterator first, InputIterator last, const Allocator &alloc = Allocator())
    : vector(alloc)
    {
        reserve(std::distance(first, last));
        for(auto i = first; i != last; ++i) push_back(*i);
    }

    vector(std::initializer_list<value_type> init, const Allocator &alloc = Allocator())
    : vector(std::begin(init), std::end(init), alloc)
    {}
    
    ~vector()
    {
        clear();
        deallocate();
    };

    vector(const vector &x);
    vector& operator=(const vector &x);

    iterator begin() noexcept
    { return first; }

    const_iterator begin() const noexcept
    { return first; }

    iterator end() noexcept
    { return last; }

    const_iterator end() const noexcept
    { return last; }

    reverse_iterator rbegin() noexcept
    { return reverse_iterator(end()); }

    const_reverse_iterator rbegin() const noexcept
    { return const_reverse_iterator(end()); }

    reverse_iterator rend() noexcept
    { return reverse_iterator(begin()); }

    const_reverse_iterator rend() const noexcept
    { return  const_reverse_iterator(begin()); }

    const_iterator cbegin() const noexcept
    { return first; }

    const_iterator cend() const noexcept
    { return last; }

    const_reverse_iterator crbegin() const noexcept
    { return const_reverse_iterator(end()); }

    const_reverse_iterator crend() const noexcept
    { return const_reverse_iterator(begin()); }
    
    size_type size() const noexcept
    { return end() - begin(); }

    bool empty() const noexcept
    { return begin() == end(); }

    size_type capacity() const noexcept
    { return reserved_last - first; }

    reference operator[](size_type i)
    { return first[i]; }

    const_reference operator[](size_type i) const
    { return first[i]; }

    reference at(size_type i)
    {
        if(i >= size()) throw std::out_of_range("index is out of range.");
        return first[i];
    }

    const_reference at(size_type i) const
    {
        if(i >= size()) throw std::out_of_range("index is out of range.");
        return first[i];
    }

    reference front()
    { return first; }

    const_reference front() const
    { return first; }

    reference back()
    { return last - 1; }

    const_reference back() const
    { return last - 1; }

    pointer data() noexcept
    { return first; }

    const_pointer data() const noexcept
    { return first; }

    void clear() noexcept
    { destroy_until(rend()); }

    void reserve(size_type sz)
    {
        if(sz <= capacity()) return;

        auto ptr = allocate(sz);
        
        auto old_first = first;
        auto old_last = last;
        auto old_capacity = capacity();

        first = ptr;
        last = first;
        reserved_last = first + sz;

        // exception-unsafe
        for(auto old_iter = old_first; old_iter != old_last; ++old_iter, ++last)
        {
            construct(last, std::move(*old_iter));
        }

        for(auto riter = reverse_iterator(old_last), rend = reverse_iterator(old_first);
            riter != rend; ++riter)
        {
            destroy(&*riter);
        }

        traits::deallocate(alloc, old_first, old_capacity);
    }

    void resize(size_type sz)
    {
        if(sz < size())
        {
            auto diff = size() - sz;
            destory_until(rbegin() + diff);
            last = first + sz;
        }
        else if(sz > size())
        {
            reserve(sz);
            for(; last != reserved_last; ++last) construct(last);
        }
    }

    void resize(size_type sz, const_reference value)
    {
        if(sz < size())
        {
            auto diff = size() - sz;
            destory_until(rbegin() + diff);
            last = first + sz;
        }
        else if(sz > size())
        {
            reserve(sz);
            for(; last != reserved_last; ++last) construct(last, value);
        }
    }

    void push_back(const_reference value)
    {
        if(size() + 1 > capacity())
        {
            auto c = (size() == 0 ? 1 : (2 * size()));
            reserve(c);
        }
        construct(last, value);
        ++last;
    }

    value_type pop_back()
    {
        value_type val = *rbegin();
        --last;
        return val;
    }

    void shrink_to_fit()
    {
        if(size() == capacity()) return;
        
        auto ptr = allocate(size());
        auto current_size = size();
        for(auto raw_ptr = ptr, iter = begin(), iter_end = end();
            iter != iter_end; ++iter, ++raw_ptr)
        {
            construct(raw_ptr, *iter);    
        }

        clear();
        deallocate();
        first = ptr;
        last = ptr + current_size;
        reserved_last = last;
    }

private:
    pointer first;
    pointer last;
    pointer reserved_last;
    allocator_type alloc;

    using traits = std::allocator_traits<allocator_type>;

    pointer allocate(size_type n)
    { return traits::allocate(alloc, n); }

    void deallocate()
    { traits::deallocate(alloc, first, capacity()); }

    void construct(pointer ptr)
    { traits::construct(alloc, ptr); }

    void construct(pointer  ptr, const_reference value)
    { traits::construct(alloc, ptr, value); }

    void construct(pointer ptr, value_type &&value)
    { traits::construct(alloc, ptr, std::move(value)); }

    void destroy(pointer ptr)
    { traits::destroy(alloc, ptr); }

    void destroy_until(reverse_iterator rend)
    {
        for (auto riter = rbegin(); riter != rend; ++riter, --last)
        {
            destroy(&*riter);
        }
    }
};

#include <iostream>
using namespace std;

int main() {
    vector<int> A;
    int q; cin >> q;
    while(q--) {
        int k; cin >> k;
        if(k == 0) {
            int x; cin >> x;
            A.push_back(x);
        } else if(k == 1) {
            int p; cin >> p;
            cout << A[p] << endl;
        } else {
            A.pop_back();
        }
    }
}


Measured memory_bytes: 3816