Submission #843547

#TimeUsernameProblemLanguageResultExecution timeMemory
843547QuadrilateralTwo Currencies (JOI23_currencies)C++17
100 / 100
3515 ms65820 KiB
#pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
#define MAXN 100010
using namespace std;

typedef long long ll;

int N, M, Q;
int parent[20][MAXN];
int depth[MAXN];
int in[MAXN], out[MAXN];
int max_height;
int dfs_ordering[MAXN];
vector<int> adj[MAXN];

typedef struct save_points {
    ll s, e, val;
    bool operator < (const save_points& right) {
        return val < right.val;
    }
} save_points;

typedef struct Query {
    ll s, t, x, y;
} Query;

vector<save_points> SP;
vector<Query> queries;
int l[MAXN], r[MAXN];
vector< pair<int, int> > roads;

void fastIO() { ios_base::sync_with_stdio(0); cin.tie(0); }

void input() {
    cin >> N >> M >> Q;
    roads.resize(N);
    for (int i = 1; i <= N - 1; i++) {
        int a, b;
        cin >> a >> b;
        adj[a].push_back(b);
        adj[b].push_back(a);
        roads[i] = { min(a, b), max(a, b) };
    }
    for (int i = 1; i <= M; i++) {
        int a, b;
        cin >> a >> b;
        save_points tmp = { roads[a].first, roads[a].second, b };
        SP.push_back(tmp);
    }
    sort(SP.begin(), SP.end());
    queries.resize(Q);
    for (int i = 0; i < Q; i++)
        cin >> queries[i].s >> queries[i].t >> queries[i].x >> queries[i].y;
}

int Euler_tour_idx, ordering_idx;

void Euler_tour(int n, int dep) { // set in, out, depth, parent
    dfs_ordering[n] = ++ordering_idx;
    in[n] = ++Euler_tour_idx;
    depth[n] = dep;
    for (int i = 0; i < adj[n].size(); i++) {
        int next = adj[n][i];
        if (in[next]) continue;
        parent[0][next] = n;
        Euler_tour(next, dep + 1);
    }
    ++Euler_tour_idx;
    out[n] = Euler_tour_idx;
}

void set_parent() { // for faster lca
    int tmp = N, cnt = 0;
    while (tmp > 1) {
        tmp >>= 1;
        cnt++;
    }
    max_height = cnt;
    for (int k = 1; k <= max_height; k++)
        for (int i = 2; i <= N; i++)
            if (parent[k - 1][i])
                parent[k][i] = parent[k - 1][parent[k - 1][i]];
}

int LCA(int a, int b) { // returns lca of node a and b
    if (depth[a] != depth[b]) {
        if (depth[a] < depth[b]) swap(a, b); // a is deeper
        ll dif = depth[a] - depth[b];
        for (ll i = 0; dif > 0; i++) {
            if (dif & 1) a = parent[i][a];
            dif >>= 1;
        }
    }

    if (a != b) {
        for (int k = max_height; 0 <= k; k--) {
            if (parent[k][a] != 0 && parent[k][a] != parent[k][b]) {
                a = parent[k][a];
                b = parent[k][b];
            }
        }
        a = parent[0][a];
    }

    return a;
}

ll tree1[8 * MAXN], tree2[8 * MAXN], tree3[8 * MAXN];

void update(ll tree[], int n, int s, int e, int tgIdx, ll val) {
    if (s == e) {
        tree[n] += val;
        return;
    }
    int lch = n << 1, rch = lch | 1, m = s + e >> 1;
    if (tgIdx <= m) update(tree, lch, s, m, tgIdx, val);
    else update(tree, rch, m + 1, e, tgIdx, val);
    tree[n] = tree[lch] + tree[rch];
}

ll query(ll tree[], int n, int s, int e, int fs, int fe) {
    if (e < fs || fe < s) return 0;
    if (fs <= s && e <= fe) return tree[n];
    int lch = n << 1, rch = lch | 1, m = s + e >> 1;
    ll left = query(tree, lch, s, m, fs, fe);
    ll right = query(tree, rch, m + 1, e, fs, fe);
    return left + right;
}

void segclear(int s = 1, int e = Euler_tour_idx, int n = 1) {
    tree1[n] = tree3[n] = 0;
    if (s == e) return;
    int m = s + e >> 1;
    segclear(s, m, n << 1);
    segclear(m + 1, e, n << 1 | 1);
}

vector<int> g[MAXN];
int ans[MAXN];
int totSP[MAXN]{};
int cnts[MAXN]{};

void solve() {
    for (int i = 0; i < MAXN; i++)
        ans[i] = -1;
    Euler_tour(1, 0); // for setting in, out, par
    set_parent(); // for faster LCA(O(logN))
    for (int i = 0; i < Q; i++) { // set for PBS
        l[i] = -1;
        r[i] = M;
    }

    for (int i = 0; i < M; i++) {
        int S = SP[i].s, E = SP[i].e, VAL = SP[i].val;
        if (in[E] <= in[S] && in[S] <= out[E]) swap(S, E);
        update(tree2, 1, 1, Euler_tour_idx, in[E], 1); // SP 추가
        update(tree2, 1, 1, Euler_tour_idx, out[E], -1);
    }

    for (int j = 0; j < Q; j++) {
        int tmp_lca = LCA(queries[j].s, queries[j].t);
        ll tmp = query(tree2, 1, 1, Euler_tour_idx, 1, in[queries[j].s]) + query(tree2, 1, 1, Euler_tour_idx, 1, in[queries[j].t]) - 2 * query(tree2, 1, 1, Euler_tour_idx, 1, in[tmp_lca]);
        totSP[j] = tmp;
    }

    while (1) {
        for (int i = 0; i < MAXN; i++)
            g[i].clear();
        segclear();
        bool flag = 0;
        for (int i = 0; i < Q; i++) {
            if (l[i] + 1 == r[i]) continue;
            flag = 1; g[l[i] + r[i] >> 1].push_back(i);
        }
        if (!flag) break;

        for (int i = 0; i < M; i++) {
            ll S = SP[i].s, E = SP[i].e, VAL = SP[i].val;
            if (in[E] <= in[S] && in[S] <= out[E]) swap(S, E);
            update(tree1, 1, 1, Euler_tour_idx, in[E], VAL); // SP (은화 가중치) 추가
            update(tree1, 1, 1, Euler_tour_idx, out[E], -VAL);
            update(tree3, 1, 1, Euler_tour_idx, in[E], 1); // SP (단순 개수) 추가
            update(tree3, 1, 1, Euler_tour_idx, out[E], -1);
            for (auto j : g[i]) {
                int tmp_lca = LCA(queries[j].s, queries[j].t);
                ll tmp = query(tree1, 1, 1, Euler_tour_idx, 1, in[queries[j].s]) + query(tree1, 1, 1, Euler_tour_idx, 1, in[queries[j].t]) - 2 * query(tree1, 1, 1, Euler_tour_idx, 1, in[tmp_lca]);
                ll tmp3 = query(tree3, 1, 1, Euler_tour_idx, 1, in[queries[j].s]) + query(tree3, 1, 1, Euler_tour_idx, 1, in[queries[j].t]) - 2 * query(tree3, 1, 1, Euler_tour_idx, 1, in[tmp_lca]);
                if (tmp <= queries[j].y) {
                    ans[j] = max((ll)ans[j], queries[j].x - totSP[j] + tmp3);
                    l[j] = i;
                }
                else r[j] = i;
            }
        }
    }
}

void output() {
    for (int i = 0; i < Q; i++) {
        if (ans[i] == -1 && queries[i].x >= totSP[i])
            ans[i] = queries[i].x - totSP[i];
        cout << ans[i] << '\n';
    }
}

int main() {
    fastIO();
    input();
    solve();
    output();
    return 0;
}

Compilation message (stderr)

currencies.cpp: In function 'void Euler_tour(int, int)':
currencies.cpp:65:23: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   65 |     for (int i = 0; i < adj[n].size(); i++) {
      |                     ~~^~~~~~~~~~~~~~~
currencies.cpp: In function 'void update(ll*, int, int, int, int, ll)':
currencies.cpp:118:44: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
  118 |     int lch = n << 1, rch = lch | 1, m = s + e >> 1;
      |                                          ~~^~~
currencies.cpp: In function 'll query(ll*, int, int, int, int, int)':
currencies.cpp:127:44: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
  127 |     int lch = n << 1, rch = lch | 1, m = s + e >> 1;
      |                                          ~~^~~
currencies.cpp: In function 'void segclear(int, int, int)':
currencies.cpp:136:15: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
  136 |     int m = s + e >> 1;
      |             ~~^~~
currencies.cpp: In function 'void solve()':
currencies.cpp:157:39: warning: unused variable 'VAL' [-Wunused-variable]
  157 |         int S = SP[i].s, E = SP[i].e, VAL = SP[i].val;
      |                                       ^~~
currencies.cpp:176:30: warning: suggest parentheses around '+' inside '>>' [-Wparentheses]
  176 |             flag = 1; g[l[i] + r[i] >> 1].push_back(i);
      |                         ~~~~~^~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...