結果
問題 | No.1030 だんしんぐぱーりない |
ユーザー |
![]() |
提出日時 | 2020-04-17 22:50:41 |
言語 | Java (openjdk 23) |
結果 |
AC
|
実行時間 | 1,666 ms / 2,000 ms |
コード長 | 5,501 bytes |
コンパイル時間 | 2,852 ms |
コンパイル使用メモリ | 91,772 KB |
実行使用メモリ | 97,404 KB |
最終ジャッジ日時 | 2024-10-03 14:36:39 |
合計ジャッジ時間 | 44,521 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 40 |
ソースコード
import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintWriter;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.function.BiFunction;public class Main {static int[] c;public static void main(String[] args) throws Exception {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String[] sa = br.readLine().split(" ");int n = Integer.parseInt(sa[0]);int k = Integer.parseInt(sa[1]);int q = Integer.parseInt(sa[2]);sa = br.readLine().split(" ");c = new int[n];for (int i = 0; i < n; i++) {c[i] = Integer.parseInt(sa[i]);}sa = br.readLine().split(" ");int[] a = new int[k];for (int i = 0; i < k; i++) {a[i] = Integer.parseInt(sa[i]) - 1;}List<List<Integer>> list = new ArrayList<>(n);for (int i = 0; i < n; i++) {list.add(new ArrayList<>());}for (int i = 0; i < n - 1; i++) {sa = br.readLine().split(" ");int e = Integer.parseInt(sa[0]) - 1;int f = Integer.parseInt(sa[1]) - 1;list.get(e).add(f);list.get(f).add(e);}SegTreeLCA lca = new SegTreeLCA(n, list, 0);SegTree<Integer> st = new SegTree<Integer>(k, -1, (o1, o2) -> {if (o1 == -1) return o2;if (o2 == -1) return o1;return lca.lca(o1, o2).i;});for (int i = 0; i < k; i++) {st.update(i, a[i]);}PrintWriter pw = new PrintWriter(System.out);for (int i = 0; i < q; i++) {sa = br.readLine().split(" ");if (sa[0].equals("1")) {int x = Integer.parseInt(sa[1]) - 1;int y = Integer.parseInt(sa[2]) - 1;st.update(x, y);} else {int l = Integer.parseInt(sa[1]) - 1;int r = Integer.parseInt(sa[2]);pw.println(lca.get(st.query(l, r)).c);}}pw.flush();br.close();}static class SegTreeLCA {int n = 2;int n2, idx;Obj[] arr;int[] first;Obj INF = new Obj(-1, Integer.MAX_VALUE, 0);/*** 初期化* @param size 頂点数* @param list 隣接リスト* @param root 根の頂点番号*/public SegTreeLCA(int size, List<List<Integer>> list, int root) {while (n < size) {n <<= 1;}n <<= 1;n2 = n * 2 - 1;idx = n - 1;arr = new Obj[n2];first = new int[size];Arrays.fill(first, -1);Obj r = new Obj(root, 0, c[root]);arr[idx] = r;first[root] = idx - n + 1;idx++;dfs(list, r, -1);for (int i = idx; i < n2; i++) {arr[i] = INF;}for (int i = n - 2; i >= 0; i--) {if (arr[i * 2 + 1].dep < arr[i * 2 + 2].dep) {arr[i] = arr[i * 2 + 1];} else {arr[i] = arr[i * 2 + 2];}}}private void dfs(List<List<Integer>> list, Obj cur, int p) {for (int ch : list.get(cur.i)) {if (ch != p) {int cmax = Math.max(cur.c, c[ch]);Obj o = new Obj(ch, cur.dep + 1, cmax);arr[idx] = o;if (first[ch] == -1) {first[ch] = idx - n + 1;}idx++;dfs(list, o, cur.i);arr[idx] = cur;idx++;}}}/*** 頂点Iのオブジェクト取得(0≦I<size)*/public Obj get(int i) {return arr[first[i] + n - 1];}/*** 頂点A,BのLCA取得(0≦A,B<size)*/public Obj lca(int a, int b) {int l = Math.min(first[a], first[b]);int r = Math.max(first[a], first[b]);return query(l, r + 1, 0, 0, n);}private Obj query(int l, int r, int k, int beg, int end) {if (end <= l || r <= beg) return INF; // 交差しないif (l <= beg && end <= r) return arr[k]; // 完全に含むObj o1 = query(l, r, k * 2 + 1, beg, (beg + end) / 2);Obj o2 = query(l, r, k * 2 + 2, (beg + end) / 2, end);if (o1.dep < o2.dep) {return o1;}return o2;}private static class Obj {int i, dep, c;public Obj(int i, int dep, int c) {this.i = i;this.dep = dep;this.c = c;}}}static class SegTree<T> {// 親へのアクセス:(n - 1) / 2// 子へのアクセス:n * 2 + 1、n * 2 + 2int n = 2; // 要素(葉)の数int n2; // 全ノード数T NA;List<T> list;BiFunction<T, T, T> func;/*** 初期化 O(N)* @param num 要素(葉)の数* @param na 無効とみなせる値* @param func 区間に対する操作が可能な関数(戻り値は新規オブジェクト)*/public SegTree(int num, T na, BiFunction<T, T, T> func) {while (n < num) n <<= 1;n2 = n * 2 - 1;NA = na;list = new ArrayList<T>(n2);for (int i = 0; i < n2; i++) list.add(NA);this.func = func;}/*** 更新 O(logN)* @param i インデックス(0~n-1)* @param x 更新値*/void update(int i, T x) {i += n - 1; // arr上でのインデックスlist.set(i, x);while (i > 0) {i = (i - 1) / 2;list.set(i, func.apply(list.get(i * 2 + 1), list.get(i * 2 + 2)));}}/*** 取得 O(logN)* インデックスl以上r未満の区間の値*/T query(int l, int r) {return query(l, r, 0, 0, n);}/*** 取得 O(logN)* インデックスl以上r未満の区間の値、beg, endにはノードkに対応する区間* query(l, r, 0, 0, n);*/private T query(int l, int r, int k, int beg, int end) {if (end <= l || r <= beg) return NA; // 交差しないif (l <= beg && end <= r) return list.get(k); // 完全に含むT v1 = query(l, r, k * 2 + 1, beg, (beg + end) / 2);T v2 = query(l, r, k * 2 + 2, (beg + end) / 2, end);return func.apply(v1, v2);}}}