Submission #1251780

#TimeUsernameProblemLanguageResultExecution timeMemory
1251780NHristovTwo Currencies (JOI23_currencies)C++20
100 / 100
871 ms63956 KiB
#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

const int N = 1e5 + 5;
const int LG = 18;

int n, m, queries;

pair < int, int > checks[N];

int s[N], t[N], x[N], y[N];
int lca[N];

vector < pair < int, int > > g[N];
pair < int, int > edges[N];

int dep[N];
int up[LG][N];
int tim = 0;
int tin[N], tout[N];

void dfsBuild(int u, int p)
{
    tin[u] = ++tim;

    for (auto [v, id] : g[u])
    {
        if (v == p)
        {
            continue;
        }

        dep[v] = dep[u] + 1;
        up[0][v] = u;

        for (int i = 1; i < LG; i++)
        {
            up[i][v] = up[i - 1][up[i - 1][v]];
        }

        dfsBuild(v, u);
    }

    tout[u] = ++tim;
}

int calcLCA(int u, int v)
{
    if (dep[u] < dep[v])
    {
        swap(u, v);
    }

    int diff = dep[u] - dep[v];

    for (int i = 0; i < LG; i++)
    {
        if ((diff & (1 << i)))
        {
            u = up[i][u];
            diff -= (1 << i);
        }
    }

    if (u == v)
    {
        return u;
    }

    for (int i = LG - 1; i >= 0; i--)
    {
        if (up[i][u] != up[i][v])
        {
            u = up[i][u];
            v = up[i][v];
        }
    }

    return up[0][u];
}

struct Fenwick
{
    int bit[2 * N];

    void update(int idx, int val)
    {
        while (idx <= 2 * n)
        {
            bit[idx] += val;
            idx += idx & (-idx);
        }
    }

    int query(int idx)
    {
        int sum = 0;

        while (idx >= 1)
        {
            sum += bit[idx];
            idx -= idx & (-idx);
        }

        return sum;
    }

    void clearFenwick()
    {
        for (int i = 1; i <= 2 * n; i++)
        {
            bit[i] = 0;
        }
    }
};

Fenwick silverPath, goldPath;

void updatePath(bool type, int idx, int sign)
{
    int u = checks[idx].second;
    int silverCoins = checks[idx].first;

    if (!type)
    {
        silverPath.update(tin[u], silverCoins * sign);
        silverPath.update(tout[u], -silverCoins * sign);
    }
    else
    {
        goldPath.update(tin[u], sign);
        goldPath.update(tout[u], -sign);
    }
}

int queryPath(bool type, int queryIdx)
{
    int st = s[queryIdx];
    int fi = t[queryIdx];

    if (!type)
    {
        return silverPath.query(tin[st]) + silverPath.query(tin[fi]) - 2 * silverPath.query(tin[lca[queryIdx]]);
    }

    return goldPath.query(tin[st]) + goldPath.query(tin[fi]) - 2 * goldPath.query(tin[lca[queryIdx]]);
}

int L[N], R[N];
int ans[N];

vector < int > v[N];

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

    cin >> n >> m >> queries;

    for (int i = 1; i < n; i++)
    {
        cin >> edges[i].first >> edges[i].second;

        g[edges[i].first].push_back({edges[i].second, i});
        g[edges[i].second].push_back({edges[i].first, i});
    }

    dfsBuild(1, 0);

    for (int i = 1; i <= m; i++)
    {
        int p, c;

        cin >> p >> c;

        if (tin[edges[p].first] < tin[edges[p].second])
        {
            checks[i] = {c, edges[p].second};
        }
        else
        {
            checks[i] = {c, edges[p].first};
        }
    }

    sort(checks + 1, checks + m + 1);

    for (int i = 1; i <= queries; i++)
    {
        cin >> s[i] >> t[i] >> x[i] >> y[i];

        lca[i] = calcLCA(s[i], t[i]);
    }

    for (int i = 1; i <= queries; i++)
    {
        L[i] = -1, R[i] = m + 1;
        ans[i] = -1;
    }

    for (int i = 1; i <= LG; i++)
    {
        bool stop = 1;

        for (int i = 0; i <= m; i++)
        {
            v[i].clear();
        }

        for (int i = 1; i <= queries; i++)
        {
            if (L[i] <= R[i])
            {
                v[(L[i] + R[i]) / 2].push_back(i);
                stop = 0;
            }
        }

        if (stop)
        {
            break;
        }

        goldPath.clearFenwick();
        silverPath.clearFenwick();

        for (int i = 1; i <= m; i++)
        {
            updatePath(1, i, +1);
        }

        for (int mid = 0; mid <= m; mid++)
        {
            if (mid)
            {
                updatePath(1, mid, -1);
                updatePath(0, mid, +1);
            }

            for (int id : v[mid])
            {
                int currSilver = queryPath(0, id);
                int currGold = queryPath(1, id);

                if (currSilver <= y[id] && currGold <= x[id])
                {
                    ans[id] = x[id] - currGold;
                    L[id] = mid;
                }
                else
                {
                    if (currGold > x[id])
                    {
                        L[id] = mid;
                    }
                    else
                    {
                        R[id] = mid;
                    }
                }
            }
        }
    }

    for (int i = 1; i <= queries; i++)
    {
        cout << ans[i] << endl;
    }

    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...