Submission #1248699

#TimeUsernameProblemLanguageResultExecution timeMemory
1248699MinhKienTwo Currencies (JOI23_currencies)C++20
100 / 100
1112 ms40616 KiB
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

#define ll long long
const int N = 2e5 + 10;

int n, m, k;
int sz[N], par[N], depth[N];
int ChainID[N], ChainHead[N], pos[N], CurChain = 1, CurPos;
int L[N], R[N], bin[N];
vector <int> g[N];
vector <int> queries[N];

struct edge {
    int u, v;

    void inp(int i) {
        scanf("%d%d", &u, &v);
        g[u].push_back(i);
        g[v].push_back(i);
    }
} e[N];

struct CheckPoint {
    int id;
    ll silver;

    bool operator < (const CheckPoint &o) const {
        return silver < o.silver;
    }

    void inp() {
        scanf("%d%lld", &id, &silver);
    }
} p[N];

struct Query {
    int s, t, gold, id, ans;
    ll silver;

    void inp(int i) {
        scanf("%d%d%d%lld", &s, &t, &gold, &silver);
        id = i;
    }

    bool operator < (const Query &o) const {
        return id < o.id;
    }
} q[N];

bool cmp_query(const Query &A, const Query &B) {
    return bin[A.id] > bin[B.id];
}

struct BIT {
    ll val[N];

    void clear() {
        fill_n(val, n + 1, 0);
    }

    void update(int p, ll VAL) {
        while (p <= n) {
            val[p] += VAL;
            p += p & -p;
        }
    }

    ll get(int p) {
        ll ret = 0;
        while (p > 0) {
            ret += val[p];
            p -= p & -p;
        }
        return ret;
    }

    ll range(int l, int r) {
        if (l > r) return 0;
        return get(r) - get(l - 1);
    }
} bit;

void input() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i < n; ++i) e[i].inp(i);
    for (int i = 1; i <= m; ++i) p[i].inp();
    sort(p + 1, p + m + 1);
    for (int i = 1; i <= k; ++i) {
        L[i] = 0;
        R[i] = m;
        q[i].inp(i);
    }
}

int DFS(int s = 1, int p = -1) {
    sz[s] = 1;
    for (int id: g[s]) {
        int z = e[id].u ^ e[id].v ^ s;
        if (z == p) continue;
        depth[z] = depth[s] + 1;
        par[z] = s;
        sz[s] += DFS(z, s);
    }
    return sz[s];
}

void HLD(int s = 1, int p = -1) {
    if (!ChainHead[CurChain]) {
        ChainHead[CurChain] = s;
    }

    ChainID[s] = CurChain;
    pos[s] = ++CurPos;

    int nxt = 0;
    for (int id: g[s]) {
        int z = e[id].u ^ e[id].v ^ s;
        if (z == p) continue;
        if (sz[nxt] < sz[z]) nxt = z;
    }

    if (!nxt) return;
    HLD(nxt, s);
    for (int id: g[s]) {
        int z = e[id].u ^ e[id].v ^ s;
        if (z == nxt || z == p) continue;
        ++CurChain;
        HLD(z, s);
    }
}

ll GetPath(int u, int v) {
    ll sum = 0;
    while (ChainID[u] != ChainID[v]) {
        if (ChainID[u] < ChainID[v]) swap(u, v);
        sum += bit.range(pos[ChainHead[ChainID[u]]], pos[u]);
        u = par[ChainHead[ChainID[u]]];
    }

    if (depth[u] > depth[v]) swap(u, v);
    sum += bit.range(pos[u] + 1, pos[v]);

    return sum;
}

bool check(int z) {
    return GetPath(q[z].s, q[z].t) <= q[z].silver;
}

void Parallel() {
    for (int i = 1; i < n; ++i) {
        if (pos[e[i].u] < pos[e[i].v]) swap(e[i].u, e[i].v);
    }

    bool ck = true;
    while (true) {
        ck = false;

        for (int i = 1; i <= k; ++i) {
            if (L[i] > R[i]) continue;
            ck = true;
            queries[(L[i] + R[i]) >> 1].push_back(i);
        }

        if (!ck) break;

        for (int z: queries[0]) {
            bin[z] = 0;
            L[z] = 1;
        }

        for (int i = 1; i <= m; ++i) {
            bit.update(pos[e[p[i].id].u], p[i].silver);

            for (int z: queries[i]) {
                if (check(z)) {
                    L[z] = i + 1;
                    bin[z] = i;
                } else R[z] = i - 1;
            }
            queries[i].clear();
        }
        bit.clear();
    }
}

void OutAns() {
    sort(q + 1, q + k + 1, cmp_query);
    int j = m;
    bit.clear();

    for (int i = 1; i <= k; ++i) {
        while (j > bin[q[i].id]) {
            bit.update(pos[e[p[j].id].u], 1);
            --j;
        }

        int need = GetPath(q[i].s, q[i].t);
        if (need <= q[i].gold) {
            q[i].ans = q[i].gold - need;
        } else {
            q[i].ans = -1;
        }
    }

    sort(q + 1, q + k + 1);
    for (int i = 1; i <= k; ++i) {
        cout << q[i].ans << "\n";
    }
}

void solve() {
    input();
    DFS();
    HLD();
    Parallel();
    OutAns();
}

int main() {
    solve();

    return 0;
}

Compilation message (stderr)

currencies.cpp: In function 'void input()':
currencies.cpp:88:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   88 |     scanf("%d%d%d", &n, &m, &k);
      |     ~~~~~^~~~~~~~~~~~~~~~~~~~~~
currencies.cpp: In member function 'void edge::inp(int)':
currencies.cpp:21:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   21 |         scanf("%d%d", &u, &v);
      |         ~~~~~^~~~~~~~~~~~~~~~
currencies.cpp: In member function 'void CheckPoint::inp()':
currencies.cpp:36:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   36 |         scanf("%d%lld", &id, &silver);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
currencies.cpp: In member function 'void Query::inp(int)':
currencies.cpp:45:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
   45 |         scanf("%d%d%d%lld", &s, &t, &gold, &silver);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...