Submission #1262077

#TimeUsernameProblemLanguageResultExecution timeMemory
1262077patgraTwo Currencies (JOI23_currencies)C++20
100 / 100
3446 ms68220 KiB
#include <bits/stdc++.h>

#define rep(a,b,c) for(auto a = (b); a != (c); a++)
#define repD(a,b,c) for(auto a = (b); a != (c); a--)
#define repIn(a, b) for(auto& a : (b))
#define repIn2(a, b, c) for(auto& [a, b] : (c))

constexpr bool dbg = 0;
#define DEBUG if constexpr(dbg)
#define DC DEBUG std::cerr
#define eol std::endl

#define ll long long
#define pb push_back

using namespace std;

struct hsh {
    ll operator()(ll x) const {
        return x ^ 2137694207777ll;
    }
};

int n, m, q;
vector<vector<pair<int, int>>> g;
vector<pair<int, int>> ogE;
vector<int> subS, inEu, eu, over;
vector<ll> qAvail, qAvail2, dep, answers;
vector<vector<int>> costs;
map<ll, int> edges;
unordered_map<ll, int, hsh> e2;
int pret;
vector<bool> off;
int squirt;
vector<ll> sqArs, Ars;
vector<int> sqAr1, Ar1;
int all;

void tAdd(int i, ll x, int times) {
    if(x < 0) x *= -1, times *= -1;
    DC << "  tAdd(" << i << ' ' << x << ' ' << times << ")" << eol;
    Ars[i] += x * times;
    sqArs[i / squirt] += x * times;
    Ar1[i] += times;
    sqAr1[i / squirt] += times;
    all += times;
}

ll tQ(ll x) {
    ll ans = 0;
    int i = 0;
    while(i < (int)edges.size() / squirt && x >= sqArs[i]) x -= sqArs[i], ans += sqAr1[i], i++;
    i *= squirt;
    while(i < (int)edges.size() && x >= Ars[i]) x -= Ars[i], ans += Ar1[i], i++;
    if(i < (int)edges.size() && Ar1[i] && Ars[i]) {
        ll base = Ars[i] / Ar1[i];
        ans += x / base;
    }
    if(i < (int)edges.size() && !Ars[i]) ans += Ar1[i];
    return ans;
}

void dfs1(int v, int p) {
    subS[v] = 1;
    repIn2(u, c, g[v]) if(u != p && !off[u]) dfs1(u, v), subS[v] += subS[u], edges[c] = 1;
}

void dfs2(int v, int p, int cen, int ove) {
    subS[v] = 1;
    inEu[v] = pret;
    eu[pret++] = v;
    over[v] = ove;
    repIn2(u, c, g[v]) if(u != p && !off[u]) dep[u] = dep[v] + c, dfs2(u, v, cen, (v == cen ? u : ove)), subS[v] += subS[u], eu[pret++] = v;
}

bool mosCmp(pair<pair<int, int>, int> a, pair<pair<int, int>, int> b) {
    auto [al, ar] = a.first;
    auto [bl, br] = b.first;
    if(al / squirt == bl / squirt) return ((al / squirt) % 2) ? ar < br : ar > br;
    return al < bl;
}

void decompose(int v, vector<pair<pair<int, int>, int>>& queries) {
    edges.clear();
    dfs1(v, 0);
    edges.erase(0);
    int cen = v;
    bool found = false;
    while(!found) {
        found = true;
        repIn2(u, c, g[cen]) if(!off[u] && subS[u] * 2 > subS[v] && subS[u] < subS[cen]) { cen = u, found = false; break; }
    }

    v = cen;
    off[cen] = true;
    pret=0;
    dep[v] = 0;
    dfs2(v, 0, v, 0);
    vector<pair<pair<int, int>, int>> mq;
    vector<vector<pair<pair<int, int>, int>>> oq(pret);
    repIn2(ab, qi, queries) {
        auto [a, b] = ab;
        if(over[a] != over[b]) mq.pb({{min(inEu[a], inEu[b]), max(inEu[a], inEu[b])}, qi});
        else oq[inEu[over[a]]].pb({ab, qi});
    }
    queries.clear();

    int lt = 0;
    repIn2(k, vl, edges) vl = lt++, e2[k] = vl;

    squirt = (int)sqrt(pret);
    rep(i, 0, (int)edges.size() / squirt) sqArs[i] = sqAr1[i] = 0;
    rep(i, 0, (int)edges.size()) Ars[i] = Ar1[i] = 0;
    all = 0;
    ranges::sort(mq, mosCmp);
    int l = 0, r = 0;
    repIn2(ab, qi, mq) {
        auto [a, b] = ab;
        while(l > a) {
            int cv = eu[l];
            int u = eu[--l];
            if(dep[u] == dep[cv]) continue;
            tAdd(e2[abs(dep[u] - dep[cv])], dep[u] - dep[cv], 1);
        }
        while(r < b) {
            int cv = eu[r];
            int u = eu[++r];
            if(dep[u] == dep[cv]) continue;
            tAdd(e2[abs(dep[u] - dep[cv])], dep[u] - dep[cv], 1);
        }
        while(l < a) {
            int cv = eu[l];
            int u = eu[++l];
            if(dep[u] == dep[cv]) continue;
            tAdd(e2[abs(dep[u] - dep[cv])], dep[u] - dep[cv], 1);
        }
        while(r > b) {
            int cv = eu[r];
            int u = eu[--r];
            if(dep[u] == dep[cv]) continue;
            tAdd(e2[abs(dep[u] - dep[cv])], dep[u] - dep[cv], 1);
        }
        auto usable = tQ(qAvail[qi]);
        DEBUG {
            DC << "For query " << qi << "\n interval eu (" << l << ' ' << r << "): ";
            rep(i, l, r + 1) DC << eu[i] << ' ';
            DC << "\n usable " << usable << "\n all " << all << eol;
        }
        if(usable + qAvail2[qi] < all) answers[qi] = -1;
        else answers[qi] = qAvail2[qi] - (all - usable);
    }

    mq.clear();
    off[v] = true;
    repIn2(u, c, g[v]) if(!off[u]) decompose(u, oq[inEu[u]]);
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> m >> q;
    ll a, b, c, d;
    ogE.resize(n - 1);
    rep(i, 0, n - 1) cin >> ogE[i].first >> ogE[i].second;
    costs.resize(n - 1);
    rep(i, 0, m) {
        cin >> a >> b;
        costs[--a].pb((int)b);
    }

    int newNodes = 0;
    rep(i, 0, n - 1) newNodes += max(0, (int)costs[i].size() - 1);
    g.resize(n + 1 + newNodes);
    newNodes = 0;
    rep(i, 0, n - 1) {
        auto [x, y] = ogE[i];
        if(costs[i].empty()) {g[x].pb({y, 0}), g[y].pb({x, 0}); continue;}
        int last = x;
        rep(j, 0, (int)costs[i].size() - 1) g[last].pb({n + 1 + newNodes, costs[i][j]}), g[n + 1 + newNodes].pb({last, costs[i][j]}), last = n + 1 + newNodes++;
        g[last].pb({y, costs[i].back()}), g[y].pb({last, costs[i].back()});
    }
    DEBUG {
        DC << "Graph :\n";
        rep(i, 1, (int)g.size()) repIn2(j, cc, g[i]) DC << i << ' ' << j << ' ' << cc << eol;
        DC << eol;
    }

    n = (int)g.size();
    subS.resize(n);
    inEu.resize(n);
    eu.resize(2 * n + 5);
    over.resize(n);
    answers.resize(q);
    dep.resize(n);
    qAvail.resize(q);
    qAvail2.resize(q);
    off.resize(n);
    sqArs.resize(m);
    sqAr1.resize(m);
    Ars.resize(m);
    Ar1.resize(m);

    vector<pair<pair<int, int>, int>> queries(q);
    rep(i, 0, q) {
        cin >> a >> b >> c >> d;
        queries[i] = {{a, b}, i};
        qAvail[i] = d;
        qAvail2[i] = c;
    }

    decompose(1, queries);
    rep(i, 0, q) cout << answers[i] << '\n';
}


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