結果
問題 | No.1418 Sum of Sum of Subtree Size |
ユーザー |
![]() |
提出日時 | 2021-03-05 23:30:08 |
言語 | Java (openjdk 23) |
結果 |
AC
|
実行時間 | 1,208 ms / 2,000 ms |
コード長 | 5,101 bytes |
コンパイル時間 | 3,203 ms |
コンパイル使用メモリ | 90,272 KB |
実行使用メモリ | 98,180 KB |
最終ジャッジ日時 | 2024-10-07 05:27:10 |
合計ジャッジ時間 | 23,975 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 41 |
ソースコード
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.ArrayDeque;import java.util.ArrayList;import java.util.Deque;import java.util.List;import java.util.function.BiFunction;public class Main {public static void main(String[] args) throws Exception {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));int n = Integer.parseInt(br.readLine());int[][] edges = new int[n - 1][2];for (int i = 0; i < n - 1; i++) {String[] sa = br.readLine().split(" ");edges[i][0] = Integer.parseInt(sa[0]) - 1;edges[i][1] = Integer.parseInt(sa[1]) - 1;}br.close();Rerooting3<Obj> r = new Rerooting3<>(n, edges, new Obj(),(o, i) -> {Obj ret = new Obj();ret.s = o.s;ret.v = o.v;return ret;},(o1, o2) -> {Obj ret = new Obj();ret.s = o1.s + o2.s;ret.v = o1.v + o2.v;return ret;},(o, i) -> {Obj ret = new Obj();ret.s = o.s + 1;ret.v = o.v + ret.s;return ret;});long ans = 0;for (int i = 0; i < n; i++) {ans += r.query(i).v;}System.out.println(ans);}static class Obj {int s;long v;}static class Rerooting3<T> {public int nodeCnt;private T identity;private BiFunction<T, Integer, T> beforeMerge;private BiFunction<T, T, T> merge;private BiFunction<T, Integer, T> afterMerge;private List<List<Integer>> adjacents;private List<List<Integer>> indexForAdjacent;private Object[][] dp;private Object[] res;/*** 初期化* @param nodeCnt 頂点数(≧1)* @param edges 木構造の辺の配列 例:{{0,1},{0,2},{1,3}}* @param identity 単位元* @param beforeMerge 指定頂点(部分木の子)を計算する関数(何もしない場合以外戻り値は新規オブジェクト)* @param merge 部分木のマージ関数(戻り値は新規オブジェクト)* @param afterMerge 指定頂点(部分木の根)の分を計算する関数(何もしない場合以外戻り値は新規オブジェクト)*/public Rerooting3(int nodeCnt, int[][] edges, T identity, BiFunction<T, Integer, T> beforeMerge,BiFunction<T, T, T> merge, BiFunction<T, Integer, T> afterMerge) {this.nodeCnt = nodeCnt;this.identity = identity;this.beforeMerge = beforeMerge;this.merge = merge;this.afterMerge = afterMerge;adjacents = new ArrayList<>(nodeCnt);indexForAdjacent = new ArrayList<>(nodeCnt);for (int i = 0; i < nodeCnt; i++) {adjacents.add(new ArrayList<>());indexForAdjacent.add(new ArrayList<>());}for (int i = 0; i < edges.length; i++) {int[] edge = edges[i];indexForAdjacent.get(edge[0]).add(adjacents.get(edge[1]).size());indexForAdjacent.get(edge[1]).add(adjacents.get(edge[0]).size());adjacents.get(edge[0]).add(edge[1]);adjacents.get(edge[1]).add(edge[0]);}dp = new Object[nodeCnt][];res = new Object[nodeCnt];for (int i = 0; i < nodeCnt; i++) {dp[i] = new Object[adjacents.get(i).size()];}if (nodeCnt == 1) {res[0] = afterMerge.apply(identity, 0);} else {initialize();}}@SuppressWarnings("unchecked")public T query(int node) {return (T) res[node];}@SuppressWarnings("unchecked")private void initialize() {int[] parents = new int[nodeCnt];int[] order = new int[nodeCnt];// InitOrderedTreeint index = 0;Deque<Integer> stack = new ArrayDeque<>();stack.addFirst(0);parents[0] = -1;while (!stack.isEmpty()) {int current = stack.pollFirst();order[index++] = current;for (int adjacent : adjacents.get(current)) {if (adjacent == parents[current]) continue;stack.addFirst(adjacent);parents[adjacent] = current;}}// FromLeaffor (int i = order.length - 1; i >= 1; i--) {int node = order[i];int parent = parents[node];T accum = identity;int parentIndex = -1;for (int j = 0; j < adjacents.get(node).size(); j++) {if (adjacents.get(node).get(j) == parent) {parentIndex = j;continue;}accum = merge.apply(accum, beforeMerge.apply((T) dp[node][j], adjacents.get(node).get(j)));}dp[parent][indexForAdjacent.get(node).get(parentIndex)] = afterMerge.apply(accum, node);}// ToLeaffor (int node : order) {T accum = identity;Object[] accumsFromTail = new Object[adjacents.get(node).size()];accumsFromTail[accumsFromTail.length - 1] = identity;for (int j = accumsFromTail.length - 1; j >= 1; j--) {accumsFromTail[j - 1] = merge.apply((T) accumsFromTail[j],beforeMerge.apply((T) dp[node][j], adjacents.get(node).get(j)));}for (int j = 0; j < accumsFromTail.length; j++) {dp[adjacents.get(node).get(j)][indexForAdjacent.get(node).get(j)] =afterMerge.apply(merge.apply(accum, (T) accumsFromTail[j]), node);accum = merge.apply(accum, beforeMerge.apply((T) dp[node][j], adjacents.get(node).get(j)));}res[node] = afterMerge.apply(accum, node);}}}}