Submission #703447

#TimeUsernameProblemLanguageResultExecution timeMemory
703447bebraValley (BOI19_valley)C++17
23 / 100
184 ms71460 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

#define dbg(x) cerr << #x << ": " << x << endl;


const int MAX_N = 1e5 + 5;
const ll INF = 1e17;
vector<pair<int, ll>> g[MAX_N];
bool special[MAX_N];
pair<int, int> edges[MAX_N];


int tin[MAX_N];
int tout[MAX_N];
int timer = 0;

ll depth[MAX_N];
ll first_down_dist[MAX_N];
// from different subtree
ll second_down_dist[MAX_N];

const int MAX_K = 20;
int binup[MAX_K][MAX_N];
ll binup_first_dist[MAX_K][MAX_N];
ll binup_second_dist[MAX_K][MAX_N];



void dfs_down(int v, int p) {
    tin[v] = timer++;

    if (special[v]) {
        first_down_dist[v] = 0;
        second_down_dist[v] = 0;
    } else {
        first_down_dist[v] = INF;
        second_down_dist[v] = INF;
    }

    vector<ll> values;
    for (const auto& [u, w] : g[v]) {
        if (u == p) continue;
        depth[u] = depth[v] + w;
        binup[0][u] = v;
        dfs_down(u, v);
        values.emplace_back(first_down_dist[u] + w);
    }
    sort(values.begin(), values.end());
    if (values.size() == 1) {
        first_down_dist[v] = min(first_down_dist[v], values[0]);
    } else if (values.size() > 1) {
        first_down_dist[v] = min(first_down_dist[v], values[0]);
        second_down_dist[v] = min(second_down_dist[v], values[1]);
    }

    if (first_down_dist[v] != INF) {
        binup_first_dist[0][v] = first_down_dist[v] - depth[v];
    } else {
        binup_first_dist[0][v] = INF;
    }
    if (second_down_dist[v] != INF) {
        binup_second_dist[0][v] = second_down_dist[v] + depth[v];
    } else {
        binup_second_dist[0][v] = INF;
    }

    tout[v] = timer;
}


ll up_dist[MAX_N];

void dfs_up(int v) {
    for (const auto& [u, w] : g[v]) {
        g[u].erase(find(g[u].begin(), g[u].end(), make_pair(v, w)));
    }
    int n = g[v].size();
    vector<ll> pref_min(n + 1, INF);
    vector<ll> suf_min(n + 1, INF);
    for (int i = 0; i < n; ++i) {
        auto [u, w] = g[v][i];
        pref_min[i + 1] = min(pref_min[i], first_down_dist[u] + w);
    }
    for (int i = n - 1; i >= 0; --i) {
        auto [u, w] = g[v][i];
        suf_min[i] = min(suf_min[i + 1], first_down_dist[u] + w);
    }
    for (int i = 0; i < n; ++i) {
        auto [u, w] = g[v][i];
        up_dist[u] = min({up_dist[v], pref_min[i], suf_min[i + 1]}) + w;
        dfs_up(u);
    }
}


bool is_parent(int p, int v) {
    return tin[p] <= tin[v] && tout[v] <= tout[p];
}

int get_lca(int u, int v) {
    if (is_parent(u, v)) return u;
    if (is_parent(v, u)) return v;

    for (int k = MAX_K - 1; k >= 0; --k) {
        if (!is_parent(binup[k][v], u)) {
            v = binup[k][v];
        }
    }
    return binup[0][v];
}

ll get_dist(int u, int v) {
    int lca = get_lca(u, v);
    return depth[u] + depth[v] - 2 * depth[lca];
}

ll get_second_dist(int u, int v) {
    // min over second_down_dist[c] + depth[c] over all vertices c in path from v to u
    if (u == v) {
        if (second_down_dist[v] != INF) {
            return second_down_dist[v] + depth[v];
        } else {
            return INF;
        }
    }
    
    if (!is_parent(u, v)) swap(u, v);
    ll res = INF;
    for (int k = MAX_K - 1; k >= 0; --k) {
        if (!is_parent(binup[k][v], u)) {
            res = min(res, binup_second_dist[k][v]);
            v = binup[k][v];
        }
    }
    res = min(res, binup_second_dist[0][v]);
    return res;
}

ll get_first_dist(int u, int v) {
    // min over first_down_dist[c] - depth[c] over all vertices c in path from v to u
    if (u == v) {
        if (first_down_dist[v] != INF) {
            return first_down_dist[v] - depth[v];
        } else {
            return INF;
        }
    }

    if (!is_parent(u, v)) swap(u, v);

    ll res = INF;
    for (int k = MAX_K - 1; k >= 0; --k) {
        if (!is_parent(binup[k][v], u)) {
            res = min(res, binup_first_dist[k][v]);
            v = binup[k][v];
        }
    }
    res = min(res, binup_first_dist[0][v]);
    return res;
}



int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, s, q, t;
    cin >> n >> s >> q >> t;
    --t;

    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        --u, --v;
        int w;
        cin >> w;
        g[u].emplace_back(v, w);
        g[v].emplace_back(u, w);
        edges[i] = {u, v};
    }

    for (int i = 0; i < s; ++i) {
        int v;
        cin >> v;
        --v;
        special[v] = true;
    }


    dfs_down(0, -1);

    up_dist[0] = INF;
    dfs_up(0);

    for (int i = 0; i < n - 1; ++i) {
        auto& [u, v] = edges[i];
        if (!is_parent(u, v)) {
            swap(u, v);
        }
    }

    for (int v = 0; v < n; ++v) {
        binup_first_dist[0][v] = min(binup_first_dist[0][v], binup_first_dist[0][binup[0][v]]);
        binup_second_dist[0][v] = min(binup_second_dist[0][v], binup_second_dist[0][binup[0][v]]);
    }

    for (int k = 1; k < MAX_K; ++k) {
        for (int v = 0; v < n; ++v) {
            binup[k][v] = binup[k - 1][binup[k - 1][v]];
            binup_first_dist[k][v] = min(binup_first_dist[k - 1][v], binup_first_dist[k - 1][binup[k - 1][v]]);
            binup_second_dist[k][v] = min(binup_second_dist[k - 1][v], binup_second_dist[k - 1][binup[k - 1][v]]);
        }
    }

    while (q--) {
        int edge, r;
        cin >> edge >> r;
        --edge, --r;
        auto [u, v] = edges[edge];

        if ((is_parent(v, r) && is_parent(v, t)) || (!is_parent(v, r) && !is_parent(v, t))) {
            cout << "escaped\n";
            continue;
        }

        if (special[r]) {
            cout << "0\n";
            continue;
        }

        ll ans = INF;
        if (is_parent(r, u)) {
            ans = min(up_dist[r], get_second_dist(r, u) - depth[r]);
        } else if (is_parent(v, r)) {
            ans = min(first_down_dist[r], get_first_dist(v, r) + depth[r]);
        } else {
            int lca = get_lca(r, u);
            ans = min({first_down_dist[r], get_first_dist(r, lca) + depth[r], get_second_dist(lca, u) - depth[lca]});
        }

        if (ans >= INF) {
            cout << "oo\n";
        } else {
            cout << ans << '\n';
        }
    }

    return 0;
}

#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...