Submission #348637

#TimeUsernameProblemLanguageResultExecution timeMemory
348637milleniumEeeeHighway Tolls (IOI18_highway)C++17
51 / 100
392 ms262144 KiB
#include "highway.h"
//#include "grader.cpp"
#include <bits/stdc++.h>
#define pii pair<int, int>
#define fr first
#define sc second
#define szof(s) (int)s.size()
#define all(s) s.begin(), s.end()
#define mk make_pair
#define pb push_back
#define ll long long
using namespace std;

const int MAXN = 130005;
const int INF = 0x3f3f3f3f;

ll from[MAXN], to[MAXN];
vector <ll> g[MAXN];
ll dist[MAXN];
ll pr[MAXN];
ll costa, costb;
ll min_path;
ll diametr;
ll n, m;
ll Q;
map <pii, ll> id;

void make_edge(ll x, ll y) {
    g[x].pb(y);
    g[y].pb(x);
}

ll find_middle_edge() {
    ll l = 0, r = m - 1;
    vector <int> w(m);
    while (l != r) {
        ll mid = (l + r) >> 1;
        for (ll i = l; i <= r; i++) {
            if (i <= mid) {
                w[i] = 1;
            } else {
                w[i] = 0;
            }
        }
        ll cur_cost = ask(w);
        Q++;
        if (cur_cost != min_path) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
}

ll get_min_path() {
    vector <int> w(m);
    for (int i = 0; i < m; i++) {
        w[i] = 0;
    }
    ll cur_cost = ask(w);
    Q++;
    return cur_cost;
}

void dfs(ll v, ll par, ll len, vector <ll> &s_sub) {
    for (int to : g[v]) {
        if (to != par) {
            s_sub.pb(id[{v, to}]);
            dfs(to, v, len + 1, s_sub);
        }
    }
}

void calc_dist_and_pr(int v, int par, int len) {
    dist[v] = len;
    pr[v] = par;
    for (int to : g[v]) {
        if (to != par) {
            calc_dist_and_pr(to, v, len + 1);
        }
    }
}

int find_s(vector <ll> s_sub) {
    vector <int> w(m, 0);
    for (ll el : s_sub) {
        w[el] = 1;
    }    
    ll cost = ask(w);
    Q++;
    ll root_to_s = (cost - min_path) / (costb - costa);
    vector <int> possible;
    for (int i = 0; i < n; i++) {
        if (dist[i] == root_to_s) {
            possible.pb(id[{i, pr[i]}]);
        }
    }
    ll l = 0, r = szof(possible) - 1;
    while (l != r) {
        ll mid = (l + r) >> 1;
        for (ll i = 0; i < m; i++) {
            w[i] = 0;
        }
        for (ll i = l; i <= mid; i++) {
            w[possible[i]] = 1;
        }
        ll cur_cost = ask(w);
        Q++;
        if (cur_cost != min_path) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    ll need_edge = possible[l];
    if (dist[from[need_edge]] == root_to_s) {
        return from[need_edge];
    } else {
        return to[need_edge];
    }
}

void find_pair(int N, vector<int> U, vector<int> V, int AA, int BB) {
    costa = AA, costb = BB;
    m = U.size();
    n = N;
    for (ll i = 0; i < m; i++) {
        from[i] = U[i];
        to[i] = V[i];
        id[{from[i], to[i]}] = i;
        id[{to[i], from[i]}] = i;
        make_edge(from[i], to[i]);
    }
    min_path = get_min_path();
    diametr = min_path / costa;
    ll mid_edge = find_middle_edge();
    ll root = from[mid_edge];
    ll need_sub = to[mid_edge];
    vector <ll> s_sub;
    s_sub.pb(id[{root, need_sub}]);
    memset(dist, -1, sizeof(dist));
    calc_dist_and_pr(need_sub, root, 1);
    dist[root] = 0;
    dfs(need_sub, root, 1, s_sub);    
    ll SS = find_s(s_sub);
    memset(dist, -1, sizeof(dist));
    calc_dist_and_pr(SS, -1, 0);
    vector <ll> possible;
    for (ll i = 0; i < n; i++) {
        if (dist[i] == diametr) {
            possible.pb(id[{i, pr[i]}]);
        }
    }
    ll l = 0, r = szof(possible) - 1;
    vector <int> w(m);
    while (l != r) {
        ll mid = (l + r) >> 1;
        for (ll i = 0; i < m; i++) {
            w[i] = 0;
        }
        for (ll i = l; i <= mid; i++) {
            w[possible[i]] = 1;
        }
        ll cur_cost = ask(w);
        Q++;
        if (cur_cost != min_path) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    ll need_edge = possible[l];
    ll TT;
    if (dist[from[need_edge]] == diametr) {
        TT = from[need_edge];
    } else {
        TT = to[need_edge];
    }
    if (SS > TT) {
        swap(SS, TT);
    }
    answer(SS, TT);
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...