제출 #1118586

#제출 시각아이디문제언어결과실행 시간메모리
1118586steveonalexTwo Currencies (JOI23_currencies)C++17
100 / 100
621 ms98056 KiB
#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
typedef unsigned long long ull;
 
#define MASK(i) (1LL << (i))
#define GETBIT(mask, i) (((mask) >> (i)) & 1)
#define ALL(v) (v).begin(), (v).end()
 
ll max(ll a, ll b){return (a > b) ? a : b;}
ll min(ll a, ll b){return (a < b) ? a : b;}
 
ll LASTBIT(ll mask){return (mask) & (-mask);}
long pop_cnt(ll mask){return __builtin_popcountll(mask);}
long ctz(ll mask){return __builtin_ctzll(mask);}
long clz(ll mask){return __builtin_clzll(mask);}
long logOf(ll mask){return 63 - clz(mask);}
 
mt19937 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
void debug(){cout.flush();}
 
template <class T1, class T2>
    bool maximize(T1 &a, T2 b){
        if (a < b) {a = b; return true;}
        return false;
    }
 
template <class T1, class T2>
    bool minimize(T1 &a, T2 b){
        if (a > b) {a = b; return true;}
        return false;
    }
 
template <class T>
    void printArr(T& container, char separator = ' ', char finish = '\n'){
        for(auto item: container) cout << item << separator;
        cout << finish;
    }
 
template <class T>
    void remove_dup(vector<T> &a){
        sort(ALL(a));
        a.resize(unique(ALL(a)) - a.begin());
    }


struct PST{
    struct Node{
        int child[2], cnt;
        ll sum; 
        Node(){memset(child, -1, sizeof child); sum = cnt = 0;}
    };

    int L, R;
    vector<Node> a;
    vector<int> version;

    PST(int _L, int _R, int _n = 1){
        L = _L, R = _R;
        a.reserve(_n); 
    }
    void add_child(int &x){
        x = a.size();
        a.push_back(Node());
    }

    void new_tree(){
        version.push_back(a.size());
        a.push_back(Node());
        build_tree(L, R, version.back());
    }

    void build_tree(int l, int r, int id){
        if (l == r) return;
        int mid = (l + r) >> 1;
        add_child(a[id].child[0]); add_child(a[id].child[1]);
        build_tree(l, mid, a[id].child[0]);
        build_tree(mid + 1, r, a[id].child[1]);
    }

    void update(int i, pair<int, ll> val, int l, int r, int prev_id, int id){
        a[id].cnt = a[prev_id].cnt + val.first;
        a[id].sum = a[prev_id].sum + val.second;
        if (l == r) {
            return;
        }
        int mid = (l + r) >> 1;
        a[id].child[0] = a[prev_id].child[0]; 
        a[id].child[1] = a[prev_id].child[1];
        if (i <= mid){
            add_child(a[id].child[0]);
            update(i, val, l, mid, a[prev_id].child[0], a[id].child[0]);
        }
        else{
            add_child(a[id].child[1]);
            update(i, val, mid + 1, r, a[prev_id].child[1], a[id].child[1]);
        }
    }

    void update(int i, pair<int, ll> val, int id = -1){
        if (id == -1) id = version.back();
        version.push_back(0);
        add_child(version.back());
        update(i, val, L, R, id, version.back());
    }

    array<ll, 3> walk(ll c, int id1, int id2, int id3){
        array<ll, 3> ans = {0, 0, 0};
        int l = L, r = R;
        ll cnt = 0, sum = 0;
        while(l < r){
            int mid= (l + r) >> 1;
            if (a[a[id1].child[0]].sum + a[a[id2].child[0]].sum - 2*a[a[id3].child[0]].sum < c){
                c -= a[a[id1].child[0]].sum + a[a[id2].child[0]].sum- 2*a[a[id3].child[0]].sum;
                cnt += a[a[id1].child[0]].cnt + a[a[id2].child[0]].cnt- 2*a[a[id3].child[0]].cnt;
                sum += a[a[id1].child[0]].sum + a[a[id2].child[0]].sum- 2*a[a[id3].child[0]].sum;
                id1 = a[id1].child[1];
                id2 = a[id2].child[1];
                id3 = a[id3].child[1];
                l = mid + 1;
            }
            else{
                id1 = a[id1].child[0];
                id2 = a[id2].child[0];
                id3 = a[id3].child[0];
                r = mid;
            }
        }
        cnt += a[id1].cnt + a[id2].cnt- 2*a[id3].cnt;
        sum += a[id1].sum + a[id2].sum- 2*a[id3].sum;
        ans[0] = l;
        ans[1] = cnt;
        ans[2] = sum;
        return ans;
    }
};

const int N = 1e5 + 69, LOG_N = 17;
const int INF = 1e9 + 69;

int n, m, q; 
vector<pair<int, int>> graph[N];
vector<ll> lmao[N];
vector<int> b;
int state[N], g[N];

int h[N], parent[N][LOG_N];

void dfs(int u, int p, int cur, PST &st){
    h[u] = h[p] + 1;
    for(int j = 1; MASK(j) < h[u]; ++j) 
        parent[u][j] = parent[parent[u][j-1]][j-1];


    state[u] = cur;
    for(pair<int, int> v: graph[u]) if (v.first != p){
        parent[v.first][0] = u;
        g[v.first] = g[u] + lmao[v.second].size();
        if (lmao[v.second].empty()){
            dfs(v.first, u, cur, st);
        }
        else{
            int _cur = cur;
            for(ll j: lmao[v.second]){
                int idx = lower_bound(ALL(b), j) - b.begin();
                st.update(idx, {1, j}, _cur);
                _cur = st.version.back();
            }
            dfs(v.first, u, _cur, st);
        }
    }
}


int LCA(int u, int v){
    if (h[u] < h[v]) swap(u, v);
    int diff = h[u] - h[v];
    for(int j = 0; j < LOG_N; ++j) if (GETBIT(diff, j))
        u = parent[u][j];

    if (u == v) return u;

    for(int j = LOG_N - 1; j>=0; --j) if (parent[u][j] != parent[v][j]){
        u = parent[u][j];
        v = parent[v][j];
    }
    return parent[u][0];
}

int main(){
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
 
    cin >> n >> m >> q;
    for(int i= 1; i<n; ++i){
        int u, v; cin >> u >> v;
        graph[u].push_back({v, i});
        graph[v].push_back({u, i});
    }


    for(int i = 0; i<m; ++i){
        int p, k; cin >> p >> k;
        lmao[p].push_back(k);
        b.push_back(k);
    }

    b.push_back(INF);
    remove_dup(b);

    m = b.size();

    PST st(0, m-1, n * 20);
    st.new_tree();
    dfs(1, 0, 0, st);


    while(q--){
        ll u, v, x, y; cin >> u >> v >> x >> y;
        int lck = LCA(u, v);


        array<ll, 3> ans = st.walk(y, state[u], state[v], state[lck]);

        int gold_cnt = g[u] + g[v] - 2 * g[lck];

        if (ans[2] <= y){
            gold_cnt -= ans[1];
        }
        else{
            ll diff = ans[2] - y;
            if (diff % b[ans[0]] == 0) diff /= b[ans[0]];
            else diff = diff / b[ans[0]] + 1;

            gold_cnt -= ans[1] - diff;
        }

        if (gold_cnt <= x) cout << x - gold_cnt << "\n";
        else cout << -1 << "\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...