某岛

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

SPOJ TWOPATHS. Two Paths

题意:求两条不相交路径的积的最大值。

分析:dfs 序维护直径 有一个非常棒的性质。。。就是可以求子树内的直径和子树外的直径。。所以我们只要再 dfs 一次,然后每次 query 出来两个直径乘一下。。可惜 O(nlogn) 也许过不了大数据。。。

#include <lastweapon/io>
using namespace lastweapon;

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

int L[N], R[N], dep[N], id[N], nn;
VI adj[N]; int n;

struct rec{
    int d, dd, ld, rd, D;
    void init(LL _d, LL _dd) {
        d = _d; dd = 2*_dd;
        D = ld = -INF; rd = _d - dd;
    }
} T[N*4];

// max d[l] + d[r] - dd[m]
// l < m <= r
// d 深度
// dd 父亲的深度

#define lx (x<<1)
#define rx (lx|1)
#define ml ((l+r)>>1)
#define mr (ml+1)
#define lc lx,l,ml
#define rc rx,mr,r
void upd(int x) {
    T[x].d = max(T[lx].d, T[rx].d);
    T[x].dd = min(T[lx].dd, T[rx].dd);
    T[x].ld = max(T[lx].ld, T[rx].ld, T[lx].d - T[rx].dd);
    T[x].rd = max(T[lx].rd, T[rx].rd, T[rx].d - T[lx].dd);
    T[x].D = max(T[lx].D, T[rx].D, T[lx].ld + T[rx].d, T[lx].d + T[rx].rd);
}

rec upd(rec l, rec r) {
    rec x;
    x.d = max(l.d, r.d);
    x.dd = min(l.dd, r.dd);
    x.ld = max(l.ld, r.ld, l.d - r.dd);
    x.rd = max(l.rd, r.rd, r.d - l.dd);
    x.D = max(l.D, r.D, l.ld + r.d, l.d + r.rd);
    return x;
}

void Build(int x, int l, int r) {
    if (l == r) {
        T[x].init(dep[id[l]], dep[id[l]]-1);
    } else {
        Build(lc);
        Build(rc);
        upd(x);
    }
}
void dfs(int u = 1, int p = 0) {
    id[L[u] = ++nn] = u;
    for (auto v: adj[u]) if (v != p) {
        dep[v] = dep[u] + 1;
        dfs(v, u);
    }
    R[u] = nn;
}

rec Query(int x, int l, int r, int a, int b) {
    /*if (b < l || r < a) {
        rec x; x.init(-INF,INF);
        return x;
    }*/
    if (a <= l && r <= b) {
        return T[x];
    } else {

        if (b < mr) return Query(lc, a, b);
        if (ml < a) return Query(rc, a, b);
        return upd(Query(lc, a, b), Query(rc, a, b));
    }
}

LL z = 0;
void gao(int u = 1, int p = 0) {
    for (auto v: adj[u]) if (v != p) {
        LL D = Query(1,1,n,L[v],R[v]).D;
        checkMax(z, D * upd(Query(1,1,n,1,L[v]-1), Query(1,1,n,R[v]+1,n)).D);

        /*cout << L[v] << " " << R[v] << " " << v << " " << Query(1,1,n,L[v],R[v]).D << " " <<
         upd(Query(1,1,n,1,L[v]-1), Query(1,1,n,R[v]+1,n)).D
         << " " << z << endl;*/
        gao(v, u);
    }
}

int main() {

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

    dep[0] = INF;

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

    if (n > 3) {
        dfs(); Build(1, 1, n); gao();
    }
    cout << z << endl;
}

没办法,只能换根 dp 了。

#include <lastweapon/io>
using namespace lastweapon;

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

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

void upd(int d[], int v) {
    if (v > d[0]) d[2] = d[1], d[1] = d[0], d[0] = v;
    else if (v > d[1]) d[2] = d[1], d[1] = v;
    else if (v > d[2]) d[2] = 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);
    }
}

int main() {

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

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

    dfs1(); dfs2();

    LL z = 0; FOR_1(i, 2, n) checkMax(z, (LL)dn[i] * up[i]);
    cout << z << endl;
}