結果

問題 No.1833 Subway Planning
ユーザー NachiaNachia
提出日時 2022-02-16 20:33:09
言語 C++17
(gcc 11.2.0 + boost 1.78.0)
結果
AC  
実行時間 243 ms / 4,000 ms
コード長 10,540 Byte
コンパイル時間 1,132 ms
使用メモリ 17,240 KB
最終ジャッジ日時 2022-04-30 01:19:40
合計ジャッジ時間 6,973 ms
ジャッジサーバーID
(参考情報)
judge15 / judge12
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
使用メモリ
testcase_00 AC 1 ms
4,900 KB
testcase_01 AC 1 ms
6,952 KB
testcase_02 AC 1 ms
4,908 KB
testcase_03 AC 1 ms
4,904 KB
testcase_04 AC 175 ms
17,144 KB
testcase_05 AC 218 ms
17,160 KB
testcase_06 AC 209 ms
17,092 KB
testcase_07 AC 234 ms
17,156 KB
testcase_08 AC 243 ms
17,100 KB
testcase_09 AC 220 ms
17,144 KB
testcase_10 AC 182 ms
17,096 KB
testcase_11 AC 217 ms
17,192 KB
testcase_12 AC 215 ms
17,172 KB
testcase_13 AC 216 ms
17,096 KB
testcase_14 AC 195 ms
17,164 KB
testcase_15 AC 206 ms
17,148 KB
testcase_16 AC 219 ms
17,240 KB
testcase_17 AC 228 ms
17,172 KB
testcase_18 AC 211 ms
16,356 KB
testcase_19 AC 207 ms
17,096 KB
testcase_20 AC 153 ms
13,928 KB
testcase_21 AC 207 ms
17,092 KB
testcase_22 AC 202 ms
16,800 KB
testcase_23 AC 2 ms
4,908 KB
testcase_24 AC 2 ms
4,904 KB
testcase_25 AC 2 ms
4,900 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <vector>
#include <algorithm>


#include <utility>

namespace nachia{
    
struct AdjacencyList{
public:
    struct AdjacencyListRange{
        using iterator = typename std::vector<int>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const int& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<int> E;
    std::vector<int> I;
public:
    AdjacencyList(int n, std::vector<std::pair<int,int>> edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = v;
            if(rev) E[--buf[v]] = u;
        }
        I = std::move(buf);
    }
    AdjacencyList(const std::vector<std::vector<int>>& edges = {}){
        int n = mn = edges.size();
        std::vector<int> buf(n+1, 0);
        for(int i=0; i<n; i++) buf[i+1] = buf[i] + edges[i].size();
        E.resize(buf[n]);
        for(int i=0; i<n; i++) for(int j=0; j<(int)edges[i].size(); j++) E[buf[i]+j] = edges[i][j];
        I = std::move(buf);
    }
    static AdjacencyList from_raw(std::vector<int> targets, std::vector<int> bounds){
        AdjacencyList res;
        res.mn = bounds.size() - 1;
        res.E = std::move(targets);
        res.I = std::move(bounds);
        return res;
    }
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int num_edges() const { return E.size(); }
    AdjacencyList reversed_edges() const {
        AdjacencyList res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(int v : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(int v : operator[](u)) res.E[--buf[v]] = u;
        res.I = std::move(buf);
        return res;
    }
};

struct AdjacencyListEdgeIndexed{
public:
    struct Edge { int to; int edgeidx; };
    struct AdjacencyListRange{
        using iterator = typename std::vector<Edge>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const Edge& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<Edge> E;
    std::vector<int> I;
public:
    AdjacencyListEdgeIndexed(int n, const std::vector<std::pair<int,int>>& edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = { v, i };
            if(rev) E[--buf[v]] = { u, i };
        }
        I = std::move(buf);
    }
    AdjacencyListEdgeIndexed() : AdjacencyListEdgeIndexed(0, {}, false) {}
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int num_edges() const { return E.size(); }
    AdjacencyListEdgeIndexed reversed_edges() const {
        AdjacencyListEdgeIndexed res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(auto [v,i] : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(auto [v,i] : operator[](u)) res.E[--buf[v]] = {u,i};
        res.I = std::move(buf);
        return res;
    }
};

} // namespace nachia

namespace nachia{

struct HeavyLightDecomposition{
private:

    int N;
    std::vector<int> P;
    std::vector<int> PP;
    std::vector<int> PD;
    std::vector<int> D;
    std::vector<int> I;

    std::vector<int> rangeL;
    std::vector<int> rangeR;

public:

    HeavyLightDecomposition(const AdjacencyList& E = AdjacencyList(1, {}, false)){
        N = E.num_vertices();
        P.assign(N, -1);
        I = {0};
        I.reserve(N);
        for(int i=0; i<(int)I.size(); i++){
            int p = I[i];
            for(int e : E[p]) if(P[p] != e){
                I.push_back(e);
                P[e] = p;
            }
        }
        std::vector<int> Z(N, 1);
        std::vector<int> nx(N, -1);
        PP.resize(N);
        for(int i=0; i<N; i++) PP[i] = i;
        for(int i=N-1; i>=1; i--){
            int p = I[i];
            Z[P[p]] += Z[p];
            if(nx[P[p]] == -1) nx[P[p]] = p;
            if(Z[nx[P[p]]] < Z[p]) nx[P[p]] = p;
        }

        for(int p : I) if(nx[p] != -1) PP[nx[p]] = p;

        PD.assign(N,N);
        PD[0] = 0;
        D.assign(N,0);
        for(int p : I) if(p != 0){
            PP[p] = PP[PP[p]];
            PD[p] = std::min(PD[PP[p]], PD[P[p]]+1);
            D[p] = D[P[p]]+1;
        }
        
        rangeL.assign(N,0);
        rangeR.assign(N,0);
        std::vector<int> dfs;
        dfs.push_back(0);
        while(dfs.size()){
            int p = dfs.back();
            rangeR[p] = rangeL[p] + Z[p];
            int ir = rangeR[p];
            dfs.pop_back();
            for(int e : E[p]) if(P[p] != e) if(e != nx[p]){
                rangeL[e] = (ir -= Z[e]);
                dfs.push_back(e);
            }
            if(nx[p] != -1){
                rangeL[nx[p]] = rangeL[p] + 1;
                dfs.push_back(nx[p]);
            }
        }

        I.resize(N);
        for(int i=0; i<N; i++) I[rangeL[i]] = i;
    }

    int depth(int p) const { return D[p]; }
    int to_seq(int vertex) const { return rangeL[vertex]; }
    int to_vtx(int seqidx) const { return I[seqidx]; }
    int parent_of(int v) const { return P[v]; }
    int heavy_child_of(int v) const {
        if(to_seq(v) == N-1) return -1;
        int cand = to_vtx(to_seq(v) + 1);
        if(PP[v] == PP[cand]) return cand;
        return v;
    }

    int lca(int u, int v) const {
        if(PD[u] < PD[v]) std::swap(u, v);
        while(PD[u] > PD[v]) u = P[PP[u]];
        while(PP[u] != PP[v]){ u = P[PP[u]]; v = P[PP[v]]; }
        return (D[u] > D[v]) ? v : u;
    }

    int dist(int u, int v) const {
        return depth(u) + depth(v) - depth(lca(u,v)) * 2;
    }

    std::vector<std::pair<int,int>> path(int r, int c, bool include_root = true, bool reverse_path = false) const {
        if(PD[c] < PD[r]) return {};
        std::vector<std::pair<int,int>> res(PD[c]-PD[r]+1);
        for(int i=0; i<(int)res.size()-1; i++){
            res[i] = std::make_pair(rangeL[PP[c]], rangeL[c]+1);
            c = P[PP[c]];
        }
        if(PP[r] != PP[c] || D[r] > D[c]) return {};
        res.back() = std::make_pair(rangeL[r]+(include_root?0:1), rangeL[c]+1);
        if(res.back().first == res.back().second) res.pop_back();
        if(!reverse_path) std::reverse(res.begin(),res.end());
        else for(auto& a : res) a = std::make_pair(N - a.second, N - a.first);
        return move(res);
    }

    std::pair<int,int> subtree(int p){
        return std::make_pair(rangeL[p], rangeR[p]);
    }

    int median(int x, int y, int z) const {
        return lca(x,y) ^ lca(y,z) ^ lca(x,z);
    }

    int la(int from, int to, int d) const {
        if(d < 0) return -1;
        int g = lca(from,to);
        int dist0 = D[from] - D[g] * 2 + D[to];
        if(dist0 < d) return -1;
        int p = from;
        if(D[from] - D[g] < d){ p = to; d = dist0 - d; }
        while(D[p] - D[PP[p]] < d){
            d -= D[p] - D[PP[p]] + 1;
            p = P[PP[p]];
        }
        return I[rangeL[p] - d];
    }
};

} // namespace nachia

#include <iostream>

using namespace std;
using i64 = long long;
using u64 = unsigned long long;
#define rep(i,n) for(int i=0; i<(int)(n); i++)


int N;

int D;
vector<pair<int,int>> edges;
vector<int> edgeC;

nachia::AdjacencyList adj;
nachia::HeavyLightDecomposition hld;

vector<int> C;
vector<int> lmaxC;
vector<int> rmaxC;
vector<int> smaxC;

vector<int> dp;

int main(){
    cin >> N;

    edges.resize(N-1);
    edgeC.resize(N-1);
    D = 0;
    for(int i=0; i<N-1; i++){
        int u,v,c; cin >> u >> v >> c; u--; v--;
        edges[i] = {u,v};
        edgeC[i] = c;
        D = max(D, c);
    }

    adj = nachia::AdjacencyList(N, edges, true);
    hld = nachia::HeavyLightDecomposition(adj);

    C.resize(N);
    for(int i=0; i<N-1; i++){
        auto [u,v] = edges[i];
        if(hld.parent_of(u) == v) C[u] = edgeC[i];
        else C[v] = edgeC[i];
    }

    lmaxC.resize(N+1);
    rmaxC.resize(N+1);
    smaxC.resize(N+1);
    for(int i=0; i<N; i++){
        smaxC[i] = C[i];
        lmaxC[hld.to_seq(i) + 1] = C[i];
        rmaxC[hld.to_seq(i)] = C[i];
    }

    for(int i=0; i<N; i++) lmaxC[i+1] = max(lmaxC[i+1], lmaxC[i]);
    for(int i=N; i>0; i--) rmaxC[i-1] = max(rmaxC[i-1], rmaxC[i]);
    for(int i=N-1; i>0; i--){
        int p = hld.to_vtx(i);
        int pp = hld.parent_of(p);
        smaxC[pp] = max(smaxC[pp], smaxC[p]);
    }


    dp.assign(N, 0);
    int ans = D;

    for(int i=N-1; i>=0; i--){
        int p = hld.to_vtx(i);
        int exmax0 = -1;
        int exmax1 = -1;
        int pans = 0;

        for(int nx : adj[p]) if(hld.parent_of(p) != nx){
            if(exmax1 == -1 || smaxC[exmax1] < smaxC[nx]){
                if(exmax1 != -1) pans = max(pans, smaxC[exmax1]);
                exmax1 = nx;
            }
            else{
                pans = max(pans, smaxC[nx]);
                continue;
            }
            if(exmax0 == -1 || smaxC[exmax0] < smaxC[exmax1]){
                swap(exmax0, exmax1);
            }
        }

        int dpupd = pans;
        if(exmax1 != -1) dpupd = max(dpupd, smaxC[exmax1]);
        if(exmax0 != -1) dpupd = max(dpupd, dp[exmax0]);
        dpupd = max(dpupd, D - C[p]);
        dp[p] = min(smaxC[p], dpupd);

        if(exmax1 != -1) pans = max(pans, dp[exmax1]);
        if(exmax0 != -1) pans = max(pans, dp[exmax0]);

        auto subtree = hld.subtree(p);
        pans = max(pans, lmaxC[subtree.first+1]);
        pans = max(pans, rmaxC[subtree.second]);
        ans = min(ans, pans);
    }

    cout << ans << '\n';

    return 0;
}
0