Submission #1294721

#TimeUsernameProblemLanguageResultExecution timeMemory
1294721vivkostovMeetings 2 (JOI21_meetings2)C++20
4 / 100
6 ms1100 KiB
#include <bits/stdc++.h>
using namespace std;

int n;
const int MAXN = 200005;
vector<int> v[MAXN];
int used[MAXN]; // used for BFS distances (1-based)
int a[MAXN], b[MAXN];
int lead, bot;
int psub[MAXN]; // sizes of hanging subtrees per diameter node
int ind[MAXN];
vector<int> dp[MAXN];
int otg[MAXN];
int mid1, mid2;

void speed() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
}

void bfs(int beg) {
    for (int i = 1; i <= n; ++i) used[i] = 0;
    queue<int> q;
    used[beg] = 1;
    q.push(beg);
    while (!q.empty()) {
        int w = q.front(); q.pop();
        for (int nb : v[w]) {
            if (!used[nb]) {
                used[nb] = used[w] + 1;
                q.push(nb);
            }
        }
    }
}

void clea(int beg, int par) {
    used[beg] = 0;
    for (int nb : v[beg]) {
        if (nb == par) continue;
        clea(nb, beg);
    }
}

void prec() {
    int to = bot, nex = 0, par = 0;
    while (to != lead) {
        for (int nb : v[to]) {
            if (nb == par) continue;
            if (used[nb] != used[to] - 1) {
                clea(nb, to);
            } else nex = nb;
        }
        par = to;
        to = nex;
    }
}

void calc_subsizes(int beg, int leadnode, int par) {
    psub[leadnode]++;
    for (int nb : v[beg]) {
        if (!used[nb] && nb != par) calc_subsizes(nb, leadnode, beg);
    }
}

int check_count(int mi) {
    int br = 0;
    for (int i = 1; i <= n; ++i) {
        if (used[i] && used[i] <= mi) br += psub[i];
    }
    return br;
}

void find_mid() {
    int L = 1, R = used[bot], mi;
    while (L <= R) {
        mi = (L + R) / 2;
        if (check_count(mi) >= (n + 1) / 2) R = mi - 1;
        else L = mi + 1;
    }
    // compute safe values for check(L) and check(L-1)
    int cL = check_count(L);
    int cLm1 = (L - 1 >= 0 ? check_count(L - 1) : 0);

    int dist1, dist2;
    if (min(cL, n - cL) >= min(cLm1, n - cLm1)) {
        dist1 = L;
        dist2 = L + 1;
    } else {
        dist1 = L - 1;
        dist2 = L;
    }
    // find nodes with used == dist1 / dist2 (if any)
    mid1 = -1; mid2 = -1;
    for (int i = 1; i <= n; ++i) {
        if (used[i] == dist1 && mid1 == -1) mid1 = i;
        if (used[i] == dist2 && mid2 == -1) mid2 = i;
    }
    // if not found (edge cases), fall back to endpoints near center of diameter
    if (mid1 == -1) mid1 = lead;
    if (mid2 == -1) mid2 = bot;
}

void get_dp(int beg, int par, int level) {
    ind[beg] = beg;
    // gather children excluding parent
    vector<int> children;
    for (int nb : v[beg]) if (nb != par) children.push_back(nb);

    if (children.empty()) {
        // real leaf
        dp[beg].clear();
        dp[beg].push_back(level);
        ind[beg] = beg;
        return;
    }

    // process children
    for (int child : children) {
        get_dp(child, beg, level + 1);
        // pick the child with largest dp vector as representative
        if (dp[ind[beg]].size() < dp[ind[child]].size()) {
            ind[beg] = ind[child];
        }
    }

    // Now merge other children into dp[ind[beg]] (small-to-large)
    int sum = 1;
    for (int child : children) {
        if (ind[child] == ind[beg]) continue;
        int sz = (int)dp[ind[child]].size();
        sum += sz;
        // dp[ind[beg]] should be >= dp[ind[child]] in size because we chose largest as ind[beg]
        for (int j = 0; j < sz; ++j) {
            if (j < (int)dp[ind[beg]].size()) {
                otg[j] = max(otg[j], dp[ind[beg]][j] + dp[ind[child]][j] - level * 2 + 1);
                dp[ind[beg]][j] = max(dp[ind[beg]][j], dp[ind[child]][j]);
            }
        }
    }
    // extend dp[ind[beg]] by 'sum' copies of level (as original logic intended)
    for (int i = 1; i <= sum; ++i) dp[ind[beg]].push_back(level);
}

int main() {
    speed();
    if (!(cin >> n)) return 0;
    for (int i = 1; i <= n; ++i) {
        v[i].clear();
        used[i] = 0;
        psub[i] = 0;
        ind[i] = 0;
        dp[i].clear();
        otg[i] = 0;
    }
    for (int i = 1; i < n; ++i) {
        cin >> a[i] >> b[i];
        v[a[i]].push_back(b[i]);
        v[b[i]].push_back(a[i]);
    }

    // find diameter endpoints
    bfs(1);
    int ma = 0;
    for (int i = 1; i <= n; ++i) {
        if (used[i] > ma) { ma = used[i]; lead = i; }
    }
    bfs(lead);
    ma = 0;
    for (int i = 1; i <= n; ++i) {
        if (used[i] > ma) { ma = used[i]; bot = i; }
    }

    // prune non-diameter subtrees (used[] marks diameter nodes with distances)
    prec();

    // compute subtree sizes hanging from each diameter node
    for (int i = 1; i <= n; ++i) {
        if (used[i]) {
            // use i as root of its hanging subtree, accumulate count into psub[i]
            calc_subsizes(i, i, 0);
        }
    }

    // choose mid nodes on diameter
    find_mid();

    // clear dp/otg again to be safe (they were zeroed initially)
    for (int i = 1; i <= n; ++i) {
        dp[i].clear();
        ind[i] = 0;
    }
    // compute dp from both midpoints
    // If mid1 == mid2, call once
    if (mid1 == mid2) {
        get_dp(mid1, 0, 1);
    } else {
        get_dp(mid1, mid2, 1);
        get_dp(mid2, mid1, 1);
    }

    // fill default for otg (fallback 1 where no better found)
    for (int i = 0; i <= n; ++i) if (!otg[i]) otg[i] = 1;

    // prepare representative indices for mid1/mid2
    int rep1 = ind[mid1];
    int rep2 = ind[mid2];

    // output answers: one per line
    for (int k = 1; k <= n; ++k) {
        if (k % 2 == 1) {
            cout << 1 << '\n';
        } else {
            int idx = k / 2 - 1;
            int s1 = (rep1 ? (int)dp[rep1].size() : 0);
            int s2 = (rep2 ? (int)dp[rep2].size() : 0);
            int ans;
            if (idx >= 0 && min(s1, s2) > idx) {
                ans = max(dp[rep1][idx] + dp[rep2][idx], otg[idx]);
            } else {
                // take whichever has the idx (if any) else use otg
                int val1 = (idx >= 0 && s1 > idx ? dp[rep1][idx] : 0);
                int val2 = (idx >= 0 && s2 > idx ? dp[rep2][idx] : 0);
                ans = max(otg[idx], max(val1, val2));
            }
            cout << ans << '\n';
        }
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...