競プロ精進日記 #61

精進や復習で解いた問題を載せていきます。

yukicoder

競プロ精進日記 #60

精進や復習で解いた問題を載せていきます。

AtCoder

競プロ精進日記 #59

精進や復習で解いた問題を載せていきます。

AtCoder

競プロ精進日記 #58

精進や復習で解いた問題を載せていきます。

Codeforces #653 (Div. 3)

  • A. Required Remainder
    n を x で割った際の余りが y より大きければ割った際の商に x をかけて y を足したものが答えで、
    それ以外ならば n を x で割った際の商から 1 を引いたものに x をかけて y を足したものが答えです。
    提出したソースコード

  • B. Multiply by 2, divide by 6
    n を 2 と 3 についてのみ素因数分解して、残りが 1 でない場合は -1 です。
    また、3 の個数が 2 の個数よりも少ない場合は -1 です。
    それ以外の場合は 3 の個数に 3 の個数から 2 の個数を引いたものを足した数が答えです。
    提出したソースコード

  • C. Move Brackets
    ( と ) の個数をそれぞれ数え、 ) の個数が ( の個数を超えた場合は ) を一番右に移動したとみなして、答えに 1 を足し、( と ) の数を合わせます。
    提出したソースコード

yukicoder

競プロ精進日記 #57

精進や復習で解いた問題を載せていきます。

yukicoder

競プロ精進日記 #56

精進や復習で解いた問題を載せていきます。

yukicoder

yukicoder No.1094 木登り / Climbing tree 解説

問題概要

  • N 頂点の重みつき無向木が与えられる
  • Q 個の質問 (以下) に答える
     1 \leq j \leq Q となる  j に関して、頂点  s_{j} と頂点  t_{j} の最短距離を求める

考えたこと

各頂点間の重みが 1 の場合はこの問題のように LCA を用いることで任意の 2 頂点間の最短距離を求めることができる。

各辺に重みを載せてあげれば同様に LCA を用いて任意の 2 頂点間の最短距離を求めることができそう。

実装

#include <bits/stdc++.h>
 
using namespace std;
 
template <typename T>
class LCA {
    public:
        int n, log_v = 0;
        vector<int> depth;
        vector<T> costs;
        vector<vector<int> > to;
        vector<vector<T> > cost;
        vector<vector<int> > parent;
 
        LCA() {}
        LCA(int n_): n(n_) {
            while ((1 << log_v) < n) ++log_v;
            depth.assign(n, 0);
            costs.assign(n, 0);
            to = vector<vector<int> >(n);
            cost = vector<vector<T> >(n);
            parent = vector<vector<int> >(log_v, vector<int>(n, 0));
        }
 
        void init(int root = 0) {
            dfs(root);
            for (int i = 0; i < log_v - 1; ++i) {
                rep (j, n) parent[i + 1][j] = parent[i][parent[i][j]];
            }
        }
 
        void addEdge(int u, int v, T c = 0) {
            to[u].push_back(v);
            to[v].push_back(u);
            cost[u].push_back(c);
            cost[v].push_back(c);
        }
 
        void dfs(int v, int p = -1, int d = 0, T c = 0) {
            if (p != -1) parent[0][v] = p;
            depth[v] = d;
            costs[v] = c;
            for (int i = 0; i < to[v].size(); ++i) {
                int e = to[v][i];
                if (e == p) continue;
                dfs(e, v, d + 1, c + cost[v][i]);
            }
        }
 
        int query(int u, int v) {
            if (depth[u] > depth[v]) swap(u, v);
            for (int i = 0; i < log_v; ++i) {
                if ((depth[v] - depth[u]) >> i & 1) v = parent[i][v];
            }
            if (u == v) return u;
            for (int i = log_v - 1; i >= 0; --i) {
                if (parent[i][u] != parent[i][v]) {
                    u = parent[i][u];
                    v = parent[i][v];
                }
            }
            return parent[0][u];
        }
 
        int length(int u, int v) {
            return depth[u] + depth[v] - 2 * depth[query(u, v)];
        }
 
        T dist(int u, int v) {
            return costs[u] + costs[v] - 2 * costs[query(u, v)];
        }
 
        // is x on the path u - v
        bool isOnPath(int u, int v, int x) {
            return length(u, x) + length(v, x) == length(u, v);
        }
};
 
int main() {
    int n, q;
    cin >> n;
    LCA<int> lca = LCA<int>(n);
    for (int i = 0; i < n - 1; ++i) {
        int a, b, c;
        cin >> a >> b >> c;
        lca.addEdge(a - 1, b - 1, c);
    }
    lca.init();
    cin >> q;
    for (int i = 0; i < q; ++i) {
        int s, t;
        cin >> s >> t;
        cout << lca.dist(s - 1, t - 1) << endl;
    }
     
    return 0;
}

終わり

確か AtCoder の解説放送で LCA やっていた気がします。
解説放送ライブラリにもあってそれを参考にしてライブラリを作った気が。。。