結果

問題 No.1976 Cut then Connect
ユーザー yuriko32
提出日時 2025-09-11 01:45:45
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
WA  
実行時間 -
コード長 7,062 bytes
コンパイル時間 2,506 ms
コンパイル使用メモリ 203,540 KB
実行使用メモリ 10,880 KB
最終ジャッジ日時 2025-09-11 01:45:51
合計ジャッジ時間 6,038 ms
ジャッジサーバーID
(参考情報)
judge2 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1 WA * 1
other AC * 7 WA * 24
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
const int INF_NEG = -1000000000;

int N;
vector<vector<int>> g;
vi parent_node;
vi depth_down;   // depth_down[u] = max distance from u to a node in its subtree (edges)
vi diam_sub;     // diameter of subtree rooted at u (edges)
vi up_depth;     // distance from u to farthest node outside its subtree (edges), or -INF if none
vi up_diam;      // diameter of the component outside u's subtree (edges)

void dfs1(int u, int p){
    parent_node[u] = p;
    depth_down[u] = 0;
    diam_sub[u] = 0;
    // collect children's depth_down and diam_sub
    vector<int> topDepths; topDepths.reserve(g[u].size());
    for(int v: g[u]){
        if(v==p) continue;
        dfs1(v, u);
        topDepths.push_back(depth_down[v]);
        diam_sub[u] = max(diam_sub[u], diam_sub[v]);
    }
    // set depth_down[u]
    int best = -1;
    for(int d: topDepths) if(d > best) best = d;
    if(best >= 0) depth_down[u] = best + 1;
    else depth_down[u] = 0;

    // maybe path through u uses top two child depths
    int a=-1,b=-1;
    for(int d: topDepths){
        if(d > a){ b = a; a = d; }
        else if(d > b){ b = d; }
    }
    if(a >= 0 && b >= 0){
        diam_sub[u] = max(diam_sub[u], a + b + 2);
    } else if(a >= 0){
        // path between u and deepest node in its child
        diam_sub[u] = max(diam_sub[u], a + 1);
    } else {
        // leaf: diam_sub[u] = 0 already
    }
}

void dfs2(int u, int p){
    // prepare arrays of candidates from children: depth_down[child] and diam_sub[child]
    int deg = g[u].size();
    // collect children (exclude parent)
    vector<int> children;
    for(int v: g[u]) if(v != p) children.push_back(v);
    int k = children.size();

    // precompute for siblings: max diam_sub among children, also top two depth_down among children
    // We will need prefix/suffix maxima for diam_sub and depth_down to exclude a child quickly.
    vector<int> prefMaxDiam(k+1, INT_MIN), sufMaxDiam(k+1, INT_MIN);
    for(int i=0;i<k;i++){
        prefMaxDiam[i+1] = max(prefMaxDiam[i], diam_sub[children[i]]);
    }
    for(int i=k-1;i>=0;i--){
        sufMaxDiam[i] = max(sufMaxDiam[i+1], diam_sub[children[i]]);
    }

    // for depths (depth_down[child] + 1 is distance from parent u to deepest in that child)
    vector<int> prefBestDepth(k+1, INF_NEG), sufBestDepth(k+1, INF_NEG);
    for(int i=0;i<k;i++){
        int val = depth_down[children[i]] + 1; // distance from u to deepest in that child
        prefBestDepth[i+1] = max(prefBestDepth[i], val);
    }
    for(int i=k-1;i>=0;i--){
        int val = depth_down[children[i]] + 1;
        sufBestDepth[i] = max(sufBestDepth[i+1], val);
    }

    // For combining two best among { up_depth[u], depth_down[sibling]+1 }, we may need top two.
    // We'll compute for each child its up_depth and up_diam then recurse.
    for(int i=0;i<k;i++){
        int v = children[i];
        // compute max diam among siblings (exclude v)
        int maxSiblingDiam = max(prefMaxDiam[i], sufMaxDiam[i+1]);
        if(maxSiblingDiam == INT_MIN) maxSiblingDiam = INF_NEG;

        // compute best depth among siblings (distance from u)
        int bestSibDepth = max(prefBestDepth[i], sufBestDepth[i+1]); // could be INF_NEG
        // candidates for distances from u to nodes not in v-subtree:
        // - up_depth[u] (distance from u to outside of u-subtree)
        // - bestSibDepth (distance from u to deepest in any sibling)
        // - also node u itself distance 0 (but when computing up_depth[v] at child we consider at least distance 1 to parent)
        int cand1 = up_depth[u]; // maybe -INF
        int cand2 = bestSibDepth; // maybe -INF

        // compute up_depth[v] (distance from v to farthest node outside v-subtree)
        // options:
        //  - go to parent u: distance 1 (to reach u)
        //  - go to parent then to outside via up_depth[u]: 1 + up_depth[u]
        //  - go to parent then to sibling deepest: 1 + bestSibDepth
        int bestToOutside = 1; // at least can reach parent (distance 1)
        if(cand1 > INF_NEG) bestToOutside = max(bestToOutside, 1 + cand1);
        if(cand2 > INF_NEG) bestToOutside = max(bestToOutside, 1 + cand2);
        up_depth[v] = bestToOutside;

        // compute up_diam[v] (diameter of component outside v-subtree)
        int cur = INF_NEG;
        // include up_diam[u]
        if(up_diam[u] > cur) cur = up_diam[u];
        // include diameters of siblings
        if(maxSiblingDiam > cur) cur = maxSiblingDiam;
        // include path that goes through u combining two best among { up_depth[u], depth_down[sib]+1 }
        // collect top two
        int x = INF_NEG, y = INF_NEG;
        if(cand1 > x){ y = x; x = cand1; }
        else if(cand1 > y){ y = cand1; }
        if(cand2 > x){ y = x; x = cand2; }
        else if(cand2 > y){ y = cand2; }
        // best single (distance from u to farthest outside)
        if(x > cur) cur = x;
        // pair
        if(y > INF_NEG){
            cur = max(cur, x + y);
        }
        // Note: cur might still be INF_NEG if there is truly nothing outside (possible when u is root and no siblings)
        if(cur == INF_NEG) cur = 0; // empty component -> diameter 0
        up_diam[v] = cur;

        // recurse
        dfs2(v, u);
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    // read tree
    int k_dummy;
    if(!(cin >> k_dummy)) return 0; // reuse var name not used
    // Actually first input is number of nodes? Problem statement here only the abstract; assume next is N and then edges?
    // For safety: this program assumes next integer is N, followed by N-1 parents: for i=2..N read parent.
    // But to be generic, let's assume input: N then N-1 lines edges or parent array. Here we follow parental array style.
    // However original user's preceding problems used parent-array format. We'll assume same: first read N then next N-1 parents for 2..N.
    int Nread = k_dummy;
    N = Nread;
    g.assign(N+1, {});
    parent_node.assign(N+1, 0);
    depth_down.assign(N+1, 0);
    diam_sub.assign(N+1, 0);
    up_depth.assign(N+1, INF_NEG);
    up_diam.assign(N+1, 0);

    // read parent array style: next N-1 integers a2..aN
    for(int i=2;i<=N;i++){
        int a; cin >> a;
        g[a].push_back(i);
        g[i].push_back(a);
    }

    // root at 1
    dfs1(1, 0);
    // for root: up_depth[root] = INF_NEG (no outside), up_diam[root] = 0
    up_depth[1] = INF_NEG;
    up_diam[1] = 0;
    dfs2(1, 0);

    // now for every edge parent-child (p - v where parent_node[v] == p), consider cut there
    long long ans = LLONG_MAX;
    for(int v=2; v<=N; ++v){
        int p = parent_node[v];
        int d1 = diam_sub[v];
        int d2 = up_diam[v];
        // radius = ceil(d/2) = (d+1)/2 using integer
        int r1 = (d1 + 1) / 2;
        int r2 = (d2 + 1) / 2;
        int cand = max( max(d1, d2), r1 + 1 + r2 );
        ans = min<long long>(ans, cand);
    }
    if(ans==LLONG_MAX) ans = 0;
    cout << ans << "\n";
    return 0;
}
0