#pragma GCC optimize("Ofast") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx") #pragma GCC optimize("unroll-loops") //#pragma warning(disable : 4996) #ifdef _MSC_VER #include #define __builtin_popcount __popcnt #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define REP(i, n) for (int i = 0; i < n; ++i) #define REPR(i, n) for (int i = n - 1; i >= 0; --i) #define FOR(i, m, n) for (int i = m; i < n; ++i) #define FORR(i, m, n) for (int i = m - 1; i >= n; --i) #define SORT(v, n) sort(v, v + n); #define VSORT(v) sort(v.begin(), v.end()); #define REVERSE(v, n) reverse(v, v + n); #define VREVERSE(v) reverse(v.begin(), v.end()) #define ll long long #define print(x) cout << (x) << '\n' #define pe(x) cout << (x) << " " #define DEBUG(x) cout << #x << ": " << x << endl #define lb(v, n) lower_bound(v.begin(), v.end(), (n)) #define ub(v, n) upper_bound(v.begin(), v.end(), (n)) //#define int long long //#define double long double #define all(x) (x).begin(), (x).end() #define print_space(v) REP(i, v.size()) cout << v[i] << ((i == v.size() - 1) ? "\n" : " ") template inline void chmin(T1& a, T2 b) { if (a > b) a = b; } template inline void chmax(T1& a, T2 b) { if (a < b) a = b; } typedef pair pii; typedef array arr3; std::random_device rd; std::mt19937 mt(rd()); constexpr ll MOD = 1e9 + 7; constexpr int MAX = 2000020; const double pi = acos(-1); constexpr double EPS = 1e-8; constexpr ll INF = 1e18; void yes(bool c) { if (c) print("Yes"); else print("No"); }; // const int mod = 1000000007; const int mod = 998244353; struct mint { ll x; // typedef long long ll; mint(ll x = 0) : x((x % mod + mod) % mod) {} mint operator-() const { return mint(-x); } mint& operator+=(const mint a) { if ((x += a.x) >= mod) x -= mod; return *this; } mint& operator-=(const mint a) { if ((x += mod - a.x) >= mod) x -= mod; return *this; } mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this; } mint operator+(const mint a) const { return mint(*this) += a; } mint operator-(const mint a) const { return mint(*this) -= a; } mint operator*(const mint a) const { return mint(*this) *= a; } mint pow(ll t) const { if (!t) return 1; mint a = pow(t >> 1); a *= a; if (t & 1) a *= *this; return a; } // for prime mod mint inv() const { return pow(mod - 2); } mint& operator/=(const mint a) { return *this *= a.inv(); } mint operator/(const mint a) const { return mint(*this) /= a; } }; istream& operator>>(istream& is, const mint& a) { return is >> a.x; } ostream& operator<<(ostream& os, const mint& a) { return os << a.x; } template struct edge { int src, to; T cost; edge(int to) : src(-1), to(to), cost(1) {} edge(int to, T cost) : src(-1), to(to), cost(cost) {} edge(int src, int to, T cost) : src(src), to(to), cost(cost) {} edge& operator=(const int& x) { to = x; return *this; } operator int() const { return to; } }; template using Edges = vector>; template using Graph = vector>; template struct HeavyLightDecomposition { Graph G; // next: child which makes heavy edge // head: head of heavy edge vector sz, par, next, head, depth, index; int N; HeavyLightDecomposition(Graph& g) : G(g) { N = G.size(); sz.assign(N, 0); par.assign(N, 0); next.assign(N, -1); head.assign(N, 0); depth.assign(N, 0); index.assign(N, 0); build(); } int dfs(int n) { int siz = 1, mx = 0; for (auto e : G[n]) { int nxt = e.to; if (nxt == par[n]) continue; par[nxt] = n; siz += dfs(nxt); if (sz[nxt] > mx) { mx = sz[nxt]; next[n] = nxt; // heavy edge } } return sz[n] = siz; } void assign_number() { queue> que; // push the head of heavy edge que.push({0, 0}); int idx = 0; while (!que.empty()) { int n = que.front().first; int d = que.front().second; que.pop(); index[n] = idx++; depth[n] = d; int h = n; head[n] = n; while (next[n] != -1) { for (auto e : G[n]) { int nxt = e.to; if (nxt == par[n] || nxt == next[n]) continue; que.push({nxt, d + 1}); } n = next[n]; index[n] = idx++; depth[n] = d; head[n] = h; } } } void build() { dfs(0); assign_number(); } int lca(int u, int v) { if (u == v) return u; if (depth[u] > depth[v]) swap(u, v); while (depth[u] < depth[v]) { v = par[head[v]]; } // if u and v begong to the same array if (head[u] == head[v]) { if (index[u] < index[v]) return u; else return v; } else { u = par[head[u]]; v = par[head[v]]; return lca(u, v); } } vector> query(int u, int v) { vector> ret; if (depth[u] > depth[v]) swap(u, v); while (depth[u] < depth[v]) { int l = index[head[v]], r = index[v] + 1; ret.push_back({l, r}); v = par[head[v]]; } // if u and v begong to the same array if (head[u] == head[v]) { if (index[u] > index[v]) swap(u, v); int l = index[u], r = index[v] + 1; ret.push_back({l, r}); } return ret; } }; template struct SegmentTree { int n; T unit; vector dat; function func; SegmentTree(const int N, T _unit, function _func) : unit(_unit), func(_func) { n = 1; //簡単のため、要素数を2のべき乗に while (n < N) n *= 2; dat.assign(2 * n, unit); } void update(int k, T a) { k += n - 1; //葉の節点 dat[k] = a; //上りながら更新 while (k > 0) { k = (k - 1) / 2; dat[k] = func(dat[k * 2 + 1], dat[k * 2 + 2]); } } T _query(int a, int b, int k, int l, int r) { //[a,b)と[l,r)が交差していなければ、funcに影響を与えない値を返す if (r <= a || b <= l) return unit; //[a,b)が[l,r)を完全に含んでいれば、この節点の値 if (a <= l && r <= b) return dat[k]; else { int vl = _query(a, b, k * 2 + 1, l, (l + r) / 2); int vr = _query(a, b, k * 2 + 2, (l + r) / 2, r); return func(vl, vr); } } //[a,b) T query(int a, int b) { return _query(a, b, 0, 0, n); } }; // auto f = [](int a, int b) {return a + b; }; // SegmentTreeseg(N,0,f); template struct DisjointSparseTable { using F = function; const F f; vector> st; DisjointSparseTable(const vector& v, const F& f) : f(f) { int b = 0; while ((1 << b) <= v.size()) ++b; st.resize(b, vector(v.size(), Semigroup())); for (int i = 0; i < v.size(); i++) st[0][i] = v[i]; for (int i = 1; i < b; i++) { int shift = 1 << i; for (int j = 0; j < v.size(); j += shift << 1) { int t = min(j + shift, (int)v.size()); st[i][t - 1] = v[t - 1]; for (int k = t - 2; k >= j; k--) st[i][k] = f(v[k], st[i][k + 1]); if (v.size() <= t) break; st[i][t] = v[t]; int r = min(t + shift, (int)v.size()); for (int k = t + 1; k < r; k++) st[i][k] = f(st[i][k - 1], v[k]); } } } Semigroup query(int l, int r) { if (l >= --r) return st[0][l]; int p = 31 - __builtin_clz(l ^ r); return f(st[p][l], st[p][r]); } }; const int SIZE = 334; int C[200010], A[200010]; int who[200010]; int par[201010]; //[l,r) int calc_par(int l, int r, HeavyLightDecomposition& hl) { int p = A[l]; int idx = l; while (idx < r) { if (idx % SIZE == 0 && idx + SIZE <= r) { p = hl.lca(p, par[idx / SIZE]); idx += SIZE; } else { p = hl.lca(p, A[idx]); idx++; } } return p; } int N, K; int update(int idx, HeavyLightDecomposition& hl) { int i = idx / SIZE; par[i] = A[i * SIZE]; FOR(j, i * SIZE, i * SIZE + SIZE) { if (j >= K) break; par[i] = hl.lca(par[i], A[j]); } return par[i]; } void solve() { cin >> N; int Q; cin >> K >> Q; Graph G(N); REP(i, N) cin >> C[i]; REP(i, K) { cin >> A[i]; A[i]--; who[A[i]] = i; } REP(i, N - 1) { int u, v; cin >> u >> v; u--, v--; if (u > v) swap(u, v); edge e(v); G[u].push_back(e); edge e2(u); G[v].push_back(e2); } HeavyLightDecomposition hl(G); auto f = [](int a, int b) { return max(a, b); }; vector v(N); REP(i, N) { v[hl.index[i]] = C[i]; } DisjointSparseTable table(v, f); // auto f = [](int a, int b) { return max(a, b); }; // SegmentTree seg(N, 0, f); // REP(i, N)seg.update(i, C[i]); // REP(i, N) seg.update(hl.index[i], C[i]); int cnt = (K + SIZE - 1) / SIZE; REP(i, cnt) { par[i] = A[i * SIZE]; REP(j, SIZE) { int v = i * SIZE + j; if (v >= K) break; int p = hl.lca(par[i], A[v]); par[i] = p; } } // REP(i, cnt) { // cout << i * SIZE << " " << i * SIZE + SIZE << ":" << par[i]+1 << endl; //} REP(_, Q) { int T; cin >> T; if (T == 2) { int l, r; cin >> l >> r; l--, r; int p = calc_par(l, r, hl); vector ps = hl.query(0, p); int res = 0; // cerr << "par:" << p + 1 << endl; for (auto pp : ps) { // cerr << pp.first+1 << " " << pp.second+1 << endl; res = max(res, table.query(pp.first, pp.second)); } // cerr << "par:" << p + 1 << endl; // int res = seg.query(0, p + 1); print(res); } else { int x, y; cin >> x >> y; x--; y--; A[x] = y; update(x, hl); // seg.update(hl.index[x], C[A[x]]); } } } signed main() { cin.tie(0); ios::sync_with_stdio(false); // int q; cin >> q; // while (q--) solve(); }