#include <iostream>
#include <cstdio>
#define Lc tree[now].lc
#define Rc tree[now].rc
#define Ls tree[now].lson
#define Rs tree[now].rson
#define V tree[now].v
#define MX 1000010
using namespace std;
int n,m;
int root[MX] = {1};//根节点坐标
int yuan[MX];//原数据
struct Node{
int lson,rson;//左右儿子的坐标
int lc,rc;//所储存的范围
int v;//(叶子节点)所储存的值
}tree[MX * 40];
int latest = 0;//树中最新的坐标
int loc;//查询/修改目标坐标
int k;//修改的值
void maketree(int l,int r)
{
int now = ++latest;//申请节点
Lc = l,Rc = r;
if (Lc == Rc)//到达叶节点,储存实际值
{
V = yuan[l];
return;
}
int mid = (l + r) / 2;
Ls = latest + 1;//记录左子节点坐标
maketree(l,mid);//构造左子节点
Rs = latest + 1;//记录右子节点坐标
maketree(mid + 1,r);//构造右子节点
}
void edit(int old)//在ver版本的坐标
{
int now = ++latest;
tree[now] = tree[old];//申请新的空间并且复制
if (Lc == Rc)//到达叶子节点,修改并返回
{
V = k;
return;
}
else//未到达叶子节点,继续递归
{
if (loc <= tree[Ls].rc)//目标节点在左子节点
{
Ls = latest + 1;//修改左子节点坐标
edit(tree[old].lson);//进入ver版本的左子节点
}
else if (loc >= tree[Rs].lc)//目标节点在右子节点
{
Rs = latest + 1;//修改右子节点坐标
edit(tree[old].rson);//进入ver版本的右子节点
}
}
}
int querry(int now)//在查询(ver)版本的坐标
{
if (Lc == Rc)//到达目标叶子节点
{
return V;
}
else
{
if (loc <= tree[Ls].rc)//目标节点在左子节点
{
querry(Ls);
}
else if (loc >= tree[Rs].lc)//目标节点在右子节点
{
querry(Rs);
}
}
}
int main()
{
scanf("%d %d",&n,&m);//读入
for (int i = 1;i <= n;i++)
{
scanf("%d",&yuan[i]);
}
maketree(1,n);//建树
int opt,ver;
for (int i = 1;i <= m;i++)
{
scanf("%d %d",&ver,&opt);
if (opt == 1)
{
scanf("%d %d",&loc,&k);
root[i] = latest + 1;//记录即将诞生的新根节点坐标
edit(root[ver]);//进入ver版本
}
else
{
scanf("%d",&loc);
root[i] = root[ver];//复制ver版本的树
printf("%d\n",querry(root[ver]));//进入ver版本
}
}
return 0;
}