Submission #1287487

#TimeUsernameProblemLanguageResultExecution timeMemory
1287487Ice_manRace (IOI11_race)C++17
0 / 100
8 ms12204 KiB
/**
 ____    ____    ____    __________________    ____    ____    ____
||I ||  ||c ||  ||e ||  ||                ||  ||M ||  ||a ||  ||n ||
||__||  ||__||  ||__||  ||________________||  ||__||  ||__||  ||__||
|/__\|  |/__\|  |/__\|  |/________________\|  |/__\|  |/__\|  |/__\|

*/

#include <iostream>
#include <vector>
#include <map>

#include "race.h"

#define maxn 500005
#define PB push_back
#define X first
#define Y second

typedef long long ll;
typedef std::pair <ll, ll> pll;

const ll INF = 4e18;

std::vector<pll> v[maxn];
int n, k;
ll ans;

// We'll use DFS small-to-large per-node maps (distances measured from the node)
std::map<ll,ll>* mp[maxn];

void dfs_sl(int node, int par)
{
    // create map for node: distance 0 -> node-count 1
    mp[node] = new std::map<ll,ll>();
    mp[node]->emplace(0LL, 1LL);

    for (auto &nb : v[node])
    {
        int to = (int)nb.X;
        ll w = nb.Y;
        if (to == par) continue;

        dfs_sl(to, node);

        // ensure mp[node] is the larger map (small-to-large)
        if (mp[node]->size() < mp[to]->size())
        {
            // swap pointers: node's map becomes child's map and vice versa
            std::swap(mp[node], mp[to]);

            // BUT the map now in mp[node] has distances relative to 'to' not 'node'.
            // We must shift all keys in mp[node] by +w and add +1 to values (nodes count),
            // because we're turning it into distances from 'node'.
            std::map<ll,ll>* shifted = new std::map<ll,ll>();
            for (auto &pr : *mp[node])
            {
                ll newd = pr.first + w;
                ll newv = pr.second + 1; // include 'node'
                auto it = shifted->find(newd);
                if (it == shifted->end()) shifted->emplace(newd, newv);
                else it->second = std::min(it->second, newv);
            }
            // delete old mp[node] contents and replace pointer
            delete mp[node];
            mp[node] = shifted;
        }
        else
        {
            // mp[node] is the larger; we will merge mp[to] into mp[node]
            // but need to shift mp[to] keys by +w and values by +1 for queries and insertion
            // first check complements (without modifying mp[node])
            for (auto &pr : *mp[to])
            {
                ll dist_from_node = pr.first + w;
                ll nodes_cnt = pr.second + 1; // include node
                ll need = (ll)k - dist_from_node;
                auto it = mp[node]->find(need);
                if (it != mp[node]->end())
                {
                    ans = std::min(ans, it->second + nodes_cnt);
                }
            }
            // then insert shifted entries
            for (auto &pr : *mp[to])
            {
                ll newd = pr.first + w;
                ll newv = pr.second + 1;
                auto it = mp[node]->find(newd);
                if (it == mp[node]->end()) mp[node]->emplace(newd, newv);
                else it->second = std::min(it->second, newv);
            }
            // free child's map
            delete mp[to];
            mp[to] = nullptr;
            continue; // next child
        }

        // If we reached here it means we swapped and mp[node] is the previous mp[to] shifted.
        // We still need to merge the remaining (smaller) mp[to] (which now sits in mp[to]) into mp[node].
        // Note: after swapping we haven't yet done the query/merge for the (old) smaller child's map:
        for (auto &pr : *mp[to])
        {
            ll dist_from_node = pr.first + w;
            ll nodes_cnt = pr.second + 1;
            // query existing mp[node] for complement
            auto it = mp[node]->find((ll)k - dist_from_node);
            if (it != mp[node]->end())
                ans = std::min(ans, it->second + nodes_cnt);
        }
        // now insert them
        for (auto &pr : *mp[to])
        {
            ll newd = pr.first + w;
            ll newv = pr.second + 1;
            auto it = mp[node]->find(newd);
            if (it == mp[node]->end()) mp[node]->emplace(newd, newv);
            else it->second = std::min(it->second, newv);
        }
        // delete child's map
        delete mp[to];
        mp[to] = nullptr;
    }

    // also check if there exists an element in mp[node] equal to k (distance from node to some node in its subtree)
    auto it = mp[node]->find((ll)k);
    if (it != mp[node]->end())
        ans = std::min(ans, it->second);
}

int best_path(int N, int K, int h[][2], int L[])
{
    n = N;
    k = K;
    ans = INF;

    // clear adjacency
    for (int i = 1; i <= n; ++i) v[i].clear();

    for (int i = 0; i < n - 1; ++i)
    {
        // input nodes in h[][] are 0-based; original code used +1 indexing
        v[h[i][0] + 1].PB({h[i][1] + 1, L[i]});
        v[h[i][1] + 1].PB({h[i][0] + 1, L[i]});
    }

    for (int i = 0; i <= n; ++i) mp[i] = nullptr;

    dfs_sl(1, 0);

    // free top-level map
    if (mp[1]) { delete mp[1]; mp[1] = nullptr; }

    if (ans == INF) return -1;
    else return (int)(ans - 1); // stored values are node counts (edges+1)
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...