#include <iostream>
#include <fstream>
#include <vector>
#define INF 2000000000
using namespace std;
class ArboreMax
{
protected:
int *aint;
int n;
public:
ArboreMax(int n) { Init(n); }
ArboreMax(int a[], int n) { Init(n); Build(a, 1, 1, n); }
virtual void Init(int n)
{
this->n = n;
aint = new int[4 * n + 1];
for (int i = 0; i <= 4 * n; i++)
aint[i] = InitInt();
}
void Build(int a[], int nod, int l, int r)
{
if (l == r)
{
aint[nod] = a[l];
return;
}
int mid = (l + r) / 2;
Build(a, 2 * nod, l, mid);
Build(a, 2 * nod + 1, mid + 1, r);
aint[nod] = Merge(aint[2 * nod], aint[2 * nod + 1]);
}
virtual int Merge(int a, int b)
{
return max(a, b);
}
virtual int InitInt() { return -2e9; }
virtual void Update(int nod, int l, int r, int p, int x)
{
if (r < p || l > p) return;
if (l == r)
{
aint[nod] = x;
return;
}
int mid = (l + r) / 2;
Update(2 * nod, l, mid, p, x);
Update(2 * nod + 1, mid + 1, r, p, x);
aint[nod] = Merge(aint[2 * nod], aint[2 * nod + 1]);
}
int Query(int nod, int l, int r, int start, int end)
{
if (r < start || l > end) return InitInt();
if (start <= l && r <= end) return aint[nod];
int mid = (l + r) / 2;
int q1 = Query(2 * nod, l, mid, start, end);
int q2 = Query(2 * nod + 1, mid + 1, r, start, end);
return Merge(q1, q2);
}
};
class ArboreMin : public ArboreMax
{
public:
ArboreMin(int n) : ArboreMax(n) {}
ArboreMin(int a[], int n) : ArboreMax(a, n) {}
virtual int InitInt() { return 2e9; }
virtual int Merge(int a, int b)
{
return min(a, b);
}
};
class ArboreSum : public ArboreMax
{
public:
ArboreSum(int n) : ArboreMax(n) {}
ArboreSum(int a[], int n) : ArboreMax(a, n) {}
virtual int InitInt() { return 0; }
virtual int Merge(int a, int b)
{
return a + b;
}
};
class ArboreGCD : public ArboreMax
{
ArboreGCD(int n) : ArboreMax(n) {}
ArboreGCD(int a[], int n) : ArboreMax(a, n) {}
virtual int InitInt() { return 0; }
virtual int Merge(int a, int b)
{
if (b == 0) return a;
return Merge(b, a % b);
}
};
class ArboreMinLazy : ArboreMin
{
protected:
int* lazy;
public:
int InitInt() { return 0; }
ArboreMinLazy(int n) : ArboreMin(n)
{
lazy = new int[4 * n + 1];
for (int i = 0; i <= 4 * n; i++)
lazy[i] = 0;
}
ArboreMinLazy(int a[], int n) : ArboreMin(a, n)
{
lazy = new int[4 * n + 1];
for (int i = 0; i <= 4 * n; i++)
lazy[i] = 0;
}
virtual void Update(int nod, int l, int r, int p, int x)
{
if (lazy[nod] != 0)
{
aint[nod] += lazy[nod];
if (l != r)
{
lazy[2 * nod] += lazy[nod];
lazy[2 * nod + 1] += lazy[nod];
}
lazy[nod] = 0;
}
if (r < p || l > p) return;
if (l == r)
{
aint[nod] = x;
return;
}
int mid = (l + r) / 2;
Update(2 * nod, l, mid, p, x);
Update(2 * nod + 1, mid + 1, r, p, x);
}
virtual void UpdateLazy(int nod, int l, int r, int start, int end, int val)
{
if (lazy[nod] != 0)
{
aint[nod] += lazy[nod];
if (l != r)
{
lazy[2 * nod] += lazy[nod];
lazy[2 * nod + 1] += lazy[nod];
}
lazy[nod] = 0;
}
if (r < start || l > end) return;
if (start <= l && r <= end)
{
aint[nod] = val;
if (l != r)
{
lazy[2 * nod] += val;
lazy[2 * nod + 1] += val;
}
return;
}
int mid = (l + r) / 2;
UpdateLazy(2 * nod, l, mid, start, end, val);
UpdateLazy(2 * nod + 1, mid + 1, r, start, end, val);
aint[nod] = Merge(aint[2 * nod], aint[2 * nod + 1]);
}
virtual int Query(int nod, int l, int r, int start, int end)
{
if (lazy[nod] != 0)
{
aint[nod] += lazy[nod];
if (l != r)
{
lazy[2 * nod] += lazy[nod];
lazy[2 * nod + 1] += lazy[nod];
}
lazy[nod] = 0;
}
if (r < start || l > end) return InitInt();
if (start <= l && r <= end) return aint[nod];
int mid = (l + r) / 2;
int q1 = Query(2 * nod, l, mid, start, end);
int q2 = Query(2 * nod + 1, mid, r, start, end);
return Merge(q1, q2);
}
};
/**
Problema Arbori De Intervale din arhiva educationala infoarena
*/
class arbint
{
private:
int a[100005], n;
public:
void Sol()
{
ifstream fin("arbint.in");
ofstream fout("arbint.out");
int i, q, op, x, y;
fin >> n >> q;
for (i = 1; i <= n; i++)
fin >> a[i];
ArboreMax aint(a, n);
while (q--)
{
fin >> op >> x >> y;
if (op == 0)
fout << aint.Query(1, 1, n, x, y) << "\n";
else
aint.Update(1, 1, n, x, y);
}
}
};
/**
Problema SubtreeQueries de pe cses.fi
- liniarizarea arborelui + arbori de intervale
*** trebuie long long ca solutia sa fie corecta
*
*/
class SubtreeQueries
{
private:
vector <int> L[200005];
int a[200005], tin[200005], tout[200005], t, n;
public:
void DFS(int k, int ant)
{
tin[k] = ++t;
for (int i : L[k])
if (i != ant)
DFS(i, k);
tout[k] = t;
}
void Sol()
{
int i, q, op, x, y;
cin >> n >> q;
for (i = 1; i <= n; i++)
cin >> a[i];
for (i = 1; i < n; i++)
{
cin >> x >> y;
L[x].push_back(y);
L[y].push_back(x);
}
ArboreSum aint(n);
DFS(1, 0);
for (i = 1; i <= n; i++)
aint.Update(1, 1, n, tin[i], a[i]);
while (q--)
{
cin >> op >> x;
if (op == 1)
{
cin >> y;
aint.Update(1, 1, n, tin[x], y);
a[x] = y;
}
else
cout << aint.Query(1, 1, n, tin[x], tout[x]) << "\n";
}
}
};
SubtreeQueries s;
arbint a;
int main()
{
a.Sol();
//s.Sol();
return 0;
}