Submission #1310146

#TimeUsernameProblemLanguageResultExecution timeMemory
1310146HostekTwo Currencies (JOI23_currencies)C++20
100 / 100
803 ms46560 KiB
// https://oj.uz/problem/view/JOI23_currencies

#include <bits/stdc++.h>

constexpr int MAXN = 100005;
constexpr int SIZIK = 200005;
constexpr int L = 18;

typedef long long ll;

std::vector<std::pair<int, int>> adj[SIZIK];
int edge_to_node[SIZIK];
int checkpoints_on_edge[SIZIK];

int depth[SIZIK], pre[SIZIK], post[SIZIK], timer = 0;
int up[SIZIK][L + 1];
int static_path_cnt[SIZIK][L + 1];

ll bit_cost[SIZIK];
int bit_cnt[SIZIK];

struct Query {
    int s, t, x;
    ll y;
};
std::vector<Query> queries;
std::vector<int> mids[SIZIK];
std::array<int, 2> q_range[SIZIK];
int silver_covered_cnt[SIZIK];
ll final_gold_ans[SIZIK];

void bit_update(int idx, ll val_cost, int val_cnt) {
    for (; idx <= timer; idx += idx & -idx) {
        bit_cost[idx] += val_cost;
        bit_cnt[idx] += val_cnt;
    }
}

void subtree_update(int u, ll val_cost, int val_cnt) {
    bit_update(pre[u], val_cost, val_cnt);
    bit_update(post[u] + 1, -val_cost, -val_cnt);
}

ll query_cost(int idx) {
    ll sum = 0;
    for (; idx > 0; idx -= idx & -idx)
        sum += bit_cost[idx];
    return sum;
}

int query_cnt(int idx) {
    int sum = 0;
    for (; idx > 0; idx -= idx & -idx)
        sum += bit_cnt[idx];
    return sum;
}

void dfs(int v, int p, int edge_idx) {
    depth[v] = depth[p] + 1;
    pre[v] = ++timer;

    if (edge_idx != -1) edge_to_node[edge_idx] = v;

    up[v][0] = p;
    for (int i = 1; i <= L; ++i)
        up[v][i] = up[up[v][i - 1]][i - 1];

    static_path_cnt[v][0] = (edge_idx != -1 ? checkpoints_on_edge[edge_idx] : 0);
    for (int i = 1; i <= L; ++i) {
        static_path_cnt[v][i] = static_path_cnt[v][i - 1] + static_path_cnt[up[v][i - 1]][i - 1];
    }

    for (auto& edge : adj[v]) {
        if (edge.first != p) {
            dfs(edge.first, v, edge.second);
        }
    }
    post[v] = timer;
}

bool is_ancestor(int u, int v) {
    return pre[u] <= pre[v] && post[u] >= post[v];
}

int lca(int u, int v) {
    if (is_ancestor(u, v)) return u;
    if (is_ancestor(v, u)) return v;
    for (int i = L; i >= 0; --i) {
        if (!is_ancestor(up[u][i], v)) u = up[u][i];
    }
    return up[u][0];
}

int get_static_cnt_up(int u, int l) {
    int res = 0;
    for (int i = L; i >= 0; --i) {
        if (!is_ancestor(up[u][i], l)) {
            res += static_path_cnt[u][i];
            u = up[u][i];
        }
    }
    if (u != l) res += static_path_cnt[u][0];
    return res;
}

int get_total_static(int u, int v) {
    int l = lca(u, v);
    return get_static_cnt_up(u, l) + get_static_cnt_up(v, l);
}

void clear_bits() {
    std::fill(bit_cost, bit_cost + timer + 2, 0);
    std::fill(bit_cnt, bit_cnt + timer + 2, 0);
}

void solve() {
    int n, m, q;
    std::cin >> n >> m >> q;

    for (int i = 1; i < n; i++) {
        int u, v;
        std::cin >> u >> v;
        adj[u].push_back({v, i});
        adj[v].push_back({u, i});
    }

    std::vector<std::pair<int, int>> CP(m);
    for (int i = 0; i < m; i++) {
        std::cin >> CP[i].first >> CP[i].second;
        checkpoints_on_edge[CP[i].first]++;
    }

    std::sort(CP.begin(), CP.end(), [](const std::pair<int, int>& a, const std::pair<int, int>& b) { return a.second < b.second; });

    dfs(1, 1, -1);

    queries.resize(q + 1);
    for (int i = 1; i <= q; i++) {
        std::cin >> queries[i].s >> queries[i].t >> queries[i].x >> queries[i].y;

        int total = get_total_static(queries[i].s, queries[i].t);
        final_gold_ans[i] = (ll)queries[i].x - total;

        q_range[i] = {0, m};
        mids[(0 + m) / 2].push_back(i);
    }

    int remaining_queries = q;

    while (remaining_queries > 0) {
        clear_bits();

        for (int i = 0; i <= m; i++) {
            if (i > 0) {
                int edge_idx = CP[i - 1].first;
                int cost = CP[i - 1].second;
                int u = edge_to_node[edge_idx];
                subtree_update(u, cost, 1);
            }

            if (mids[i].empty()) continue;

            for (int q_idx : mids[i]) {
                const auto& Q = queries[q_idx];
                int l = lca(Q.s, Q.t);

                ll path_cost = query_cost(pre[Q.s]) + query_cost(pre[Q.t]) - 2 * query_cost(pre[l]);
                int path_cnt = query_cnt(pre[Q.s]) + query_cnt(pre[Q.t]) - 2 * query_cnt(pre[l]);

                if (path_cost <= Q.y) {
                    silver_covered_cnt[q_idx] = path_cnt;
                    q_range[q_idx][0] = i + 1;
                } else {
                    q_range[q_idx][1] = i - 1;
                }

                int L_Range = q_range[q_idx][0];
                int R_Range = q_range[q_idx][1];

                if (L_Range <= R_Range) {
                    mids[(L_Range + R_Range) / 2].push_back(q_idx);
                } else {
                    remaining_queries--;
                }
            }
            mids[i].clear();
        }
    }

    for (int i = 1; i <= q; i++) {
        ll res = final_gold_ans[i] + silver_covered_cnt[i];
        std::cout << std::max(-1LL, res) << '\n';
    }
}

int main() {
    std::ios_base::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);

    solve();

    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...