제출 #878340

#제출 시각아이디문제언어결과실행 시간메모리
878340boris_mihov자매 도시 (APIO20_swap)C++17
100 / 100
333 ms49056 KiB
#include "swap.h"
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cassert>
#include <vector>
#include <queue>
 
typedef long long llong;
const int MAXN = 100000 + 10;
const int MAXLOG = 17;
const int INF  = 2e9;

int n, m;
struct Sparse
{
    int par[MAXLOG][MAXN];
    int max[MAXLOG][MAXN];
    int dep[MAXN];

    void build(int p[], int e[], int d[])
    {
        for (int i = 1 ; i <= n ; ++i)
        {
            par[0][i] = p[i];
            max[0][i] = e[i];
            dep[i] = d[i];
        }

        for (int log = 1 ; (1 << log) <= n ; ++log)
        {
            for (int i = 1 ; i <= n ; ++i)
            {
                par[log][i] = par[log - 1][par[log - 1][i]];
                max[log][i] = std::max(max[log - 1][i], max[log - 1][par[log - 1][i]]);
            }
        }
    }

    void equalize(int &u, int v, int &res)
    {
        for (int log = MAXLOG - 1 ; log >= 0 ; --log)
        {
            if (dep[par[log][u]] >= dep[v])
            {
                res = std::max(res, max[log][u]);
                u = par[log][u];
            }
        }
    }

    void calcLCA(int &u, int v, int &res)
    {
        if (u == v)
        {
            return;
        }

        for (int log = MAXLOG - 1 ; log >= 0 ; --log)
        {
            if (par[log][u] != par[log][v])
            {
                res = std::max(res, max[log][u]);
                res = std::max(res, max[log][v]);
                u = par[log][u];
                v = par[log][v];
            }
        }

        res = std::max(res, max[0][v]);
        res = std::max(res, max[0][u]);
        u = par[0][u];
    }

    int findLCA(int u, int v)
    {
        int res = 0;
        if (dep[u] < dep[v])
        {
            std::swap(u, v);
        }

        equalize(u, v, res);
        calcLCA(u, v, res);
        return u;
    }

    int findMAX(int u, int v)
    {
        int res = 0;
        if (dep[u] < dep[v])
        {
            std::swap(u, v);
        }

        equalize(u, v, res);
        calcLCA(u, v, res);
        return res;
    }
};

struct DSU
{
    int par[MAXN];
    int dep[MAXN];

    void build()
    {
        std::iota(par + 1, par + 1 + n, 1);
        std::fill(dep + 1, dep + 1 + n, 1);
    }

    int find(int node)
    {
        if (par[node] == node) return node;
        return par[node] = find(par[node]);
    }

    void connect(int u, int v)
    {
        u = find(u);
        v = find(v);

        if (u == v)
        {
            return;
        }

        if (dep[u] > dep[v])
        {
            std::swap(u, v);
        }

        if (dep[u] == dep[v])
        {
            dep[v]++;
        }

        par[u] = v;
    }

    bool areConnected(int u, int v)
    {
        return find(u) == find(v);
    }
};

struct Edge
{
    int u, v;
    int dist;

    friend bool operator < (const Edge &a, const Edge &b)
    {
        return a.dist < b.dist;
    }
};

int p[MAXN];
int e[MAXN];
int dep[MAXN];
int minD[MAXN];
bool vis[MAXN];
std::priority_queue <std::pair <int,int>> relax;
std::vector <std::pair <int,int>> g[MAXN];
std::vector <std::pair <int,int>> t[MAXN];
std::vector <Edge> edges;
Sparse sparse;
DSU dsu;

void buildDFS(int node, int par)
{
    p[node] = par;
    dep[node] = dep[par] + 1;

    for (const auto &[u, d] : t[node])
    {
        if (u == par)
        {
            continue;
        }

        e[u] = d;
        buildDFS(u, node);
    }
}

void init(int N, int M, std::vector<int> U, std::vector<int> V, std::vector<int> W) 
{
    n = N; m = M;
    for (int i = 0 ; i < M ; ++i)
    {
        U[i]++; V[i]++;
        g[U[i]].emplace_back(V[i], W[i]);
        g[V[i]].emplace_back(U[i], W[i]);
        edges.push_back({U[i], V[i], W[i]});
    }

    std::fill(minD + 1, minD + 1 + n, INF);
    for (int i = 1 ; i <= n ; ++i)
    {
        std::sort(g[i].begin(), g[i].end(), [&](auto x, auto y)
        {
            return x.second < y.second;
        });

        if (g[i].size() >= 3)
        {
            minD[i] = g[i][2].second;
        }
    }

    dsu.build();
    std::sort(edges.begin(), edges.end());
    for (const auto &[u, v, d] : edges)
    {
        if (dsu.areConnected(u, v))
        {
            minD[u] = std::min(minD[u], d);
            minD[v] = std::min(minD[v], d);
        } else
        {
            t[u].emplace_back(v, d);
            t[v].emplace_back(u, d);
            dsu.connect(u, v);
        }
    }

    buildDFS(1, 0);
    sparse.build(p, e, dep);

    for (int i = 1 ; i <= n ; ++i)
    {
        relax.push({-minD[i], i});
    }
    
    while (!relax.empty())
    {
        auto [dist, node] = relax.top();
        relax.pop();

        if (vis[node])
        {
            continue;
        }

        vis[node] = true;
        for (const auto &[u, d] : t[node])
        {
            if (minD[u] > std::max(minD[node], d))
            {
                minD[u] = std::max(minD[node], d);
                relax.push({-minD[u], u});
            }
        }
    }
}
 
int getMinimumFuelCapacity(int x, int y) 
{
    x++; y++;
    int res = sparse.findMAX(x, y);
    res = std::max(res, minD[x]);
    res = std::max(res, minD[y]);
    if (res == INF) return -1;
    return res;
}
#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...