某岛

… : "…アッカリ~ン . .. . " .. .
June 5, 2023

Luogu P3629. [APIO2010] 巡逻

求两次直径的高级做法好像已经烂大街了。。
这里贴一下更常规的换根 dp。。

做法就是 Two Paths 多考虑一种情况即可~~

#include <lastweapon/io>
using namespace lastweapon;

const int N = int(3e5) + 9;

int dn[N], up[N]; // 子树内直径,子树外直径
int d[N][4], e[N]; // 子数内 top4 最长距离,子树外最长距离
VI adj[N]; int n, K, z;

void upd(int d[], int v) {
    if (v > d[0]) d[3] = d[2], d[2] = d[1], d[1] = d[0], d[0] = v;
    else if (v > d[1]) d[3] = d[2], d[2] = d[1], d[1] = v;
    else if (v > d[2]) d[3] = d[2], d[2] = v;
    else if (v > d[3]) d[3] = v;
}

void dfs1(int u = 1, int p = 0) {
    for (auto v: adj[u]) if (v != p) {
        dfs1(v, u);
        upd(d[u], d[v][0] + 1);
        checkMax(dn[u], dn[v]);
    }
    checkMax(dn[u], d[u][0] + d[u][1]);
}

void dfs2(int u = 1, int p = 0) {
    for (auto v: adj[u]) if (v != p) {
        checkMax(up[v], up[u]);
        checkMax(e[v], e[u] + 1);
        int t = d[v][0] + 1;
        if (d[u][0] == t) {
            checkMax(up[v], d[u][1] + d[u][2]);
            checkMax(up[v], d[u][1] + e[u]);
            checkMax(e[v], d[u][1] + 1);
        }
        else {
            if (d[u][1] == t) checkMax(up[v], d[u][0] + d[u][2]);
            else checkMax(up[v], d[u][0] + d[u][1]);
            checkMax(up[v], d[u][0] + e[u]);
            checkMax(e[v], d[u][0] + 1);
        }
        dfs2(v, u);
    }

    if (K == 2) checkMax(z, dn[u] + up[u]);
    upd(d[u], e[u]); checkMax(z, d[u][0] + d[u][1] + (K == 2 ? d[u][2] + d[u][3] : 0));
}

int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif

    RD(n, K); DO(n-1) {
        int x, y; RD(x, y);
        adj[x].PB(y);
        adj[y].PB(x);
    }

    dfs1(); dfs2();
    cout << 2*(n-1) - z + K << endl;
}