#include <iostream>
#include <vector>
#include <deque>
#include <random>
#include <cassert>

using namespace std;

mt19937 randgen;

struct Treap {
  struct Node {
    int count; // # of things in the subtree
    unsigned int priority;

    Node* lch;
    Node* rch;
    Node* par;

    bool lazy;
    
    int value;

    Node(int new_value) {
      count = 1;
      priority = randgen();
      lch = 0;
      rch = 0;
      par = 0;

      lazy = false;

      value = new_value;
    }
    
    void update() {
      count = 1;
      if (lch)
        count += lch->count;
      if (rch)
        count += rch->count;
    }

    void propagate() {
      if (lazy) {
        swap(lch, rch);
        if (lch)
          lch->lazy ^= 1;
        if (rch)
          rch->lazy ^= 1;
        lazy = false;
      }
    }
  };

  deque<Node> nodes;
  Node* root = 0;

  // the first `count` should end up in the left tree, rest in the right
  pair<Node*, Node*> split(int count, Node* cur) {
    if (cur == 0) return {0, 0};

    cur->propagate();
    
    pair<Node*, Node*> result;
    if (count == 0 || cur->lch && count <= cur->lch->count) {
      auto ret = split(count, cur->lch);
      cur->lch = ret.second;
      if (cur->lch)
        cur->lch->par = cur;
      result = {ret.first, cur};
    } else {
      if (cur->lch) count -= cur->lch->count;
      count--;
      
      auto ret = split(count, cur->rch);
      cur->rch = ret.first;
      if (cur->rch)
        cur->rch->par = cur;
      result = {cur, ret.second};
    }
    cur->par = 0;
    cur->update();
    return result;
  }

  Node* merge(Node* left, Node* right) {
    if (left == 0) return right;
    if (right == 0) return left;

    left->propagate();
    right->propagate();

    Node* top;
    if (left->priority < right->priority) {
      left->rch = merge(left->rch, right);
      if (left->rch)
        left->rch->par = left;
      top = left;
    } else {
      right->lch = merge(left, right->lch);
      if (right->lch)
        right->lch->par = right;
      top = right;
    }
    top->update();
    return top;
  }

  Node* push_back(int value) {
    nodes.push_back(Node(value));
    auto created = &nodes.back();
    auto cur = merge(root, created);
    root = cur;
    return created;
  }

  Node* find(Node* cur, int count) {
    assert(cur);
    cur->propagate();
    
    if (cur->lch) {
      if (count < cur->lch->count)
        return find(cur->lch, count);
      count -= cur->lch->count;
    }

    if (count == 0)
      return cur;
    count--;

    if (cur->rch)
      return find(cur->rch, count);

    return 0;
  }
};

int main () {
  ios::sync_with_stdio(false);
  cin.tie(0);

  int n, qc;
  cin >> n >> qc;

  vector<Treap::Node*> nodeof (n + 1);
  Treap treap;
  for (int i = 0; i <= n; i++)
    nodeof[i] = treap.push_back(i);

  for (int i = 0; i < qc; i++) {
    int typ;
    cin >> typ;

    if (typ == 1) {
      int l, r;
      cin >> l >> r;

      auto [LM, R] = treap.split(r + 1, treap.root);
      auto [L, M] = treap.split(l, LM);
      if (M)
        M->lazy ^= 1;

      LM = treap.merge(L, M);
      treap.root = treap.merge(LM, R);
    } else if (typ == 2) {
      int x;
      cin >> x;

      auto node = treap.find(treap.root, x);
      assert(node);
      cout << node->value << '\n';
    } else {
      int y;
      cin >> y;

      auto cur = nodeof[y];
      int pos = cur->lch ? cur->lch->count : 0;
      if (cur->lazy)
        pos = cur->count - pos - 1;
          
      while (cur->par) {
        auto par = cur->par;
        assert(cur == par->lch || cur == par->rch);

        if (cur == par->rch) {
          pos++;
          if (par->rch)
            pos += par->rch->count;
        }

        if (par->lazy)
          pos = par->count - pos - 1;

        cur = par;
      }

      cout << pos << '\n';
    }
  }
}
