Submission #1336833

#TimeUsernameProblemLanguageResultExecution timeMemory
1336833aaaaaaaaTwo Currencies (JOI23_currencies)C++20
100 / 100
1391 ms91280 KiB
#include <bits/stdc++.h>
using namespace std;

const int mxN = 1e5 + 100;
const int mxB = 20;

#define all(x) x.begin(), x.end()

vector<int> point[mxN];
vector<pair<int, int>> adj[mxN];
vector<pair<long long, int>> checkpoints;
vector<tuple<long long, long long, int, int, int, int>> Query;
vector<int> euler;
int tin[mxN], tout[mxN], st[mxN], en[mxN], stt[mxN], enn[mxN], depth[mxN], leader[mxN], tim = -1;
pair<int, int> dp[mxN * 4][mxB];
pair<long long, int> seg[mxN * 4];
long long ans[mxN];

pair<long long, int> combine(const pair<long long, int> &left, const pair<long long, int> &right){
    return {left.first + right.first, left.second + right.second};
}

void update(int idx, pair<long long, int> val){
    idx += tim;
    seg[idx].first += val.first, seg[idx].second += val.second;
    while(idx > 1){
        idx >>= 1;
        seg[idx] = combine(seg[idx << 1], seg[idx << 1 | 1]);
    }
}

pair<long long, int> query(int r){
   int l = 0;
   r += tim;
   pair<long long, int> ans = {0, 0};
   while(l <= r){
    if(l & 1) ans = combine(ans, seg[l ++]);
    if(r & 1 ^ 1) ans = combine(ans, seg[r --]);
    l >>= 1, r >>= 1;
   }
   return ans;
}

void dfs(int u = 1, int par = 0){
    tin[u] = ++tim, st[u] = (int) euler.size(), depth[u] = depth[par] + 1;
    euler.push_back(u);
    for(auto [v, id] : adj[u]){
        if(v ^ par){
            leader[id] = v;
            dfs(v, u);
            euler.push_back(u);
        }
    }
    en[u] = (int) euler.size();
    euler.push_back(u);
    tout[u] = ++tim;
}

void build(){
    int n = (int) euler.size();
    for(int i = 0; i < n; ++i){
        dp[i][0] = {depth[euler[i]], euler[i]};
    }
    for(int j = 1; j < mxB; ++j){
        for(int i = 0; i + (1 << j) - 1 < n; ++i){
            dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
        }
    }
}

int lca(int u, int v){
    int l = en[u], r = en[v];
    if(l > r) swap(l, r);
    int k = __lg(r - l + 1);
    return min(dp[l][k], dp[r - (1 << k) + 1][k]).second;
}

pair<long long, int> path_sum(int u, int v){
    int lc = lca(u, v);
    pair<long long, int> ulc = query(tin[u]), vlc = query(tin[v]), l_lc = query(tin[lc]);
    return  {(long long) ulc.first + vlc.first - 2 * l_lc.first, ulc.second + vlc.second - 2 * l_lc.second};
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n, m, q;
    cin >> n >> m >> q;

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

    dfs();
    build();

    for(int i = 1; i <= m; ++i){
        int edge_id, silver;
        cin >> edge_id >> silver;
        checkpoints.push_back({silver, edge_id});
        update(tin[leader[edge_id]], {0, 1});
        update(tout[leader[edge_id]], {0, -1});
    }

    sort(all(checkpoints));

    for(int i = 0; i < q; ++i) {
        int u, v, gold;
        long long silver;
        cin >> u >> v >> gold >> silver;
        pair<long long, int> x = path_sum(u, v);
        Query.push_back({silver, gold, u, v, i, x.second});
        stt[i] = 0, enn[i] = m - 1, ans[i] = -1;
        point[(stt[i] + enn[i]) / 2].push_back(i);
        if(x.second <= gold) ans[i] = gold - x.second;
    }

    for(auto [v, i] : checkpoints) {
        update(tin[leader[i]], {0, -1});
        update(tout[leader[i]], {0, 1});
    }

    for(int _ = 0; _ < mxB; ++_){
        for(int i = 0; i < m; ++i){
            auto [___, edge_id] = checkpoints[i];
            update(tin[leader[edge_id]], {___, 1});
            update(tout[leader[edge_id]], {-___, -1});

            for(auto que : point[i]){
                auto [silver, gold, u, v, id, total] = Query[que];
                pair<long long, int> cur = path_sum(u, v);
                if(cur.first <= silver){
                    ans[id] = max(ans[id], gold - total + cur.second);
                    stt[id] = i + 1;
                }else{
                    enn[id] = i - 1;
                }
            }

            point[i].clear();
        }

        for(int i = 0; i < q; ++i){
            if(stt[i] <= enn[i]) point[(stt[i] + enn[i]) / 2].push_back(i);
        }

        for(int i = 0; i < m; ++i){
            auto [___, edge_id] = checkpoints[i];
            update(tin[leader[edge_id]], {-___, -1});
            update(tout[leader[edge_id]], {___, 1});
        }
    }

    for(int i = 0; i < q; ++i) cout << ans[i] << "\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...