제출 #1348415

#제출 시각아이디문제언어결과실행 시간메모리
1348415MisterReaperTwo Currencies (JOI23_currencies)C++20
100 / 100
753 ms121288 KiB
#include <bits/stdc++.h>

using i64 = long long;

#ifdef DEBUG 
    #include "/home/ahmetalp/Desktop/Workplace/debug.h"
#else
    #define debug(...) void(23)
#endif

int n;
std::vector<int> all;

struct node {
    i64 sum = 0;
    int cnt = 0;
    int lc = 0;
    int rc = 0;
    node() {}
    node(const node& nd) : sum(nd.sum), cnt(nd.cnt), lc(nd.lc), rc(nd.rc) {}
};

std::vector<node> tree(1);

void pull(int v) {
    tree[v].sum = tree[tree[v].lc].sum + tree[tree[v].rc].sum;
    tree[v].cnt = tree[tree[v].lc].cnt + tree[tree[v].rc].cnt;
}

int new_node(int v) {
    tree.emplace_back(tree[v]);
    return int(tree.size()) - 1;
}

int new_node() {
    tree.emplace_back();
    return int(tree.size()) - 1;
}

int build(int l, int r) {
    int v = new_node();
    if (l == r) {
        return v;
    }
    int mid = (l + r) >> 1;
    tree[v].lc = build(l, mid);
    tree[v].rc = build(mid + 1, r);
    pull(v);
    return v;
}

int modify(int v, int l, int r, int p) {
    int nv = new_node(v);
    if (l == r) {
        tree[nv].sum += all[p];
        tree[nv].cnt += 1;
        return nv;
    }
    int mid = (l + r) >> 1;
    if (p <= mid) {
        tree[nv].lc = modify(tree[nv].lc, l, mid, p);
    } else {
        tree[nv].rc = modify(tree[nv].rc, mid + 1, r, p);
    }
    pull(nv);
    return nv;
}

std::pair<i64, int> operator* (std::pair<i64, int> lhs, int rhs) {
    return {lhs.first * rhs, lhs.second * rhs};
}
std::pair<i64, int> operator* (int lhs, std::pair<i64, int> rhs) {
    return {rhs.first * lhs, rhs.second * lhs};
}
std::pair<i64, int> operator+ (std::pair<i64, int> lhs, std::pair<i64, int> rhs) {
    return {lhs.first + rhs.first, lhs.second + rhs.second};
}
std::pair<i64, int> operator- (std::pair<i64, int> lhs, std::pair<i64, int> rhs) {
    return {lhs.first - rhs.first, lhs.second - rhs.second};
}

std::pair<i64, int> get(int v, int l, int r, int ql, int qr) {
    if (ql == l && r == qr) {
        return {tree[v].sum, tree[v].cnt};
    }
    int mid = (l + r) >> 1;
    if (qr <= mid) {
        return get(tree[v].lc, l, mid, ql, qr);
    } else if (mid + 1 <= ql) {
        return get(tree[v].rc, mid + 1, r, ql, qr);
    } else {
        return get(tree[v].lc, l, mid, ql, mid)
             + get(tree[v].rc, mid + 1, r, mid + 1, qr);
    }
}

constexpr int max_N = int(1E5) + 5;
constexpr int LG = 17;

int N;
int M;
int Q;
int E[max_N][2];
int P[max_N];
int C[max_N];
std::vector<int> adj[max_N];
std::vector<int> csts[max_N];
int roots[max_N];
int dep[max_N];
int par[LG][max_N];

void dfs(int v) {
    for (auto i : adj[v]) {
        int u = E[i][0] ^ E[i][1] ^ v;
        adj[u].erase(std::find(adj[u].begin(), adj[u].end(), i));
        roots[u] = new_node(roots[v]);
        for (auto j : csts[i]) {
            roots[u] = modify(roots[u], 0, n - 1, C[j]);
        }
        dep[u] = dep[v] + 1;
        par[0][u] = v;
        dfs(u);
    }
}

int lca(int a, int b) {
    if (dep[a] < dep[b]) {
        std::swap(a, b);
    }
    int d = dep[a] - dep[b];
    for (int i = LG - 1; i >= 0; --i) {
        if (d >> i & 1) {
            a = par[i][a];
        }
    }
    if (a == b) {
        return a;
    }
    for (int i = LG - 1; i >= 0; --i) {
        if (par[i][a] != par[i][b]) {
            a = par[i][a];
            b = par[i][b];
        }
    }
    return par[0][a];
}

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

    std::cin >> N >> M >> Q;

    for (int i = 1; i < N; ++i) {
        std::cin >> E[i][0] >> E[i][1];
        --E[i][0], --E[i][1];
        adj[E[i][0]].emplace_back(i);
        adj[E[i][1]].emplace_back(i);
    }

    for (int i = 0; i < M; ++i) {
        std::cin >> P[i] >> C[i];
        all.emplace_back(C[i]);
        csts[P[i]].emplace_back(i);
    }

    n = int(all.size());
    std::sort(all.begin(), all.end());
    all.erase(std::unique(all.begin(), all.end()), all.end());

    for (int i = 0; i < M; ++i) {
        C[i] = int(std::lower_bound(all.begin(), all.end(), C[i]) - all.begin());
    }

    dep[0] = 0;
    par[0][0] = 0;
    roots[0] = build(0, n - 1);
    dfs(0);

    for (int i = 1; i < LG; ++i) {
        for (int j = 0; j < N; ++j) {
            par[i][j] = par[i - 1][par[i - 1][j]];
        }
    }

    while (Q--) {
        int S;
        int T;
        int X;
        i64 Y;
        std::cin >> S >> T >> X >> Y;
        --S, --T;
        int l = lca(S, T);
        debug(S, T, l);
        int cnt = (get(roots[S], 0, n - 1, 0, n - 1)
                 + get(roots[T], 0, n - 1, 0, n - 1)
                 - 2 * get(roots[l], 0, n - 1, 0, n - 1)).second;
        int lo = -1, hi = n - 1;
        while (lo < hi) {
            int mid = (lo + hi + 1) >> 1;
            auto pi = get(roots[S], 0, n - 1, 0, mid)
                    + get(roots[T], 0, n - 1, 0, mid)
                    - 2 * get(roots[l], 0, n - 1, 0, mid);
            if (pi.first <= Y) {
                lo = mid;
            } else {
                hi = mid - 1;
            }
        }
        debug(lo);
        if (lo == n - 1) {
            std::cout << X << '\n';
        } else {
            std::pair<i64, int> bef;
            if (lo == -1) {
                bef = {0, 0};
            } else {
                bef = get(roots[S], 0, n - 1, 0, lo)
                    + get(roots[T], 0, n - 1, 0, lo)
                    - 2 * get(roots[l], 0, n - 1, 0, lo);
            }
            int d = (Y - bef.first) / all[lo + 1];
            debug(cnt, bef, d);
            std::cout << std::max(-1, X - (cnt - bef.second - d)) << '\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...