1 条题解

  • 0
    @ 2025-8-24 22:48:49

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 5k_sync_closer
    数据结构真可爱。

    搬运于2025-08-24 22:48:49,当前版本为作者最后更新于2023-07-29 20:56:35,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    出题人题解。

    x(u,v)x(u,v)uvu\to v 路径边权和,y(u,v)y(u,v)uvu\to v 路径点权和。

    题目中求 x(a,p)+x(b,p)+2x(p,q)=x(a,b)+2x(p,q)x(a,p)+x(b,p)+2x(p,q)=x(a,b)+2x(p,q) 最小的前提下 y(a,p)+y(b,p)+2y(p,q)2sp=y(a,b)+2y(p,q)spy(a,p)+y(b,p)+2y(p,q)-2s_p=y(a,b)+2y(p,q)-s_p 最大,

    x(a,b),y(a,b)x(a,b),y(a,b) 是定值,只需令 x(p,q)x(p,q) 最小的前提下 2y(p,q)sp2y(p,q)-s_p 最大。

    考虑对每个 aba\to b 路径上的 pp 维护出 x(p,q)x(p,q) 最小值以及此时 2y(p,q)sp2y(p,q)-s_p 最大值。

    换根 DP 维护之。设 fp,0/1f_{p,0/1}qqxx 子树内时 x(p,q)x(p,q) 的最小值 / 次小值,则容易得到状态转移方程:

    $$\begin{aligned} f_{p,0}&=\min(\{f_{q,0}+x(p,q)|q\in son_p\}\cup\{0\})\\ f_{p,1}&=\mathop{\operatorname{secondmin}}(\{f_{q,0}+x(p,q)|q\in son_p\}\cup\{0\}) \end{aligned} $$

    转移时记录 2y(p,q)sp2y(p,q)-s_p 最大值。

    gp,0/1g_{p,0/1}x(p,q)x(p,q) 的最小值 / 次小值,则 gpg_pfp,gfapf_p,g_{fa_p} 转移而来,gfapg_{fa_p}ffap,gfafapf_{fa_p},g_{fa_{fa_p}} 转移而来,ffapf_{fa_p} 可能fpf_p 转移而来,存在重复计算。

    需要记录 kpk_p 为转移到 gpg_p 的点,从而消除重复计算。

    则有状态转移方程:

    $$\begin{aligned} g_{p,0}&=\min\{f_{p,0},g_{fa_p,[k_{fa_p}=p]}+x(p,fa_p)\}\\ g_{p,1}&=\mathop{\operatorname{secondmin}}\{f_{p,0},f_{p,1},g_{fa_p,[k_{fa_p}=p]}+x(p,fa_p)\} \end{aligned} $$

    转移时记录 2y(p,q)sp2y(p,q)-s_p 最大值。

    则问题转化为求静态树链最小值,用树上倍增维护之。

    #include <cstdio>
    #include <algorithm>
    #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
    using namespace std;
    char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
    inline int R()
    {
        int r = 0;
        bool f = 0;
        char c = getchar();
        while (c < '0' || c > '9')
            f = c == '-', c = getchar();
        while (c >= '0' && c <= '9')
            r = r * 10 + c - '0', c = getchar();
        return f ? -r : r;
    }
    void P(long long x)
    {
        if (x < 0)
            *O++ = '-', x = -x;
        if (x >= 10)
            P(x / 10);
        *O++ = x % 10 + '0';
    }
    struct S
    {
        long long x, y, p;
        S operator+(S b) { return {x + b.x, y + b.y}; }
        bool operator<(S b) const { return x == b.x ? y > b.y : x < b.x; }
    } Q, F[300050][2], C[300050][20];
    struct E
    {
        int v, w, t;
    } e[1000050];
    int n, m, c, a[300050], d[300050], h[300050], f[300050][20];
    long long s[300050];
    void A(int u, int v, int w)
    {
        e[++c] = {v, w, h[u]};
        h[u] = c;
    }
    void D1(int u)
    {
        for (int i = h[u], v; i; i = e[i].t)
            if (!d[v = e[i].v])
            {
                d[v] = d[u] + 1;
                f[v][0] = u;
                for (int i = 1; f[v][i - 1]; ++i)
                    f[v][i] = f[f[v][i - 1]][i - 1];
                s[v] = s[u] + a[v];
                D1(v);
                S X = F[v][0] + S{e[i].w, a[v] << 1};
                X.p = v;
                if (X < F[u][0])
                    F[u][1] = F[u][0], F[u][0] = X;
                else if (X < F[u][1])
                    F[u][1] = X;
            }
    }
    void D2(int u, int k)
    {
        for (int i = h[u], v; i; i = e[i].t)
            if ((v = e[i].v) != k)
            {
                S X = F[u][F[u][0].p == v] + S{e[i].w, a[u] << 1};
                X.p = u;
                if (X < F[v][0])
                    F[v][1] = F[v][0], F[v][0] = X;
                else if (X < F[v][1])
                    F[v][1] = X;
                D2(v, u);
            }
    }
    void D3(int u, int k)
    {
        for (int i = h[u], v; i; i = e[i].t)
            if ((v = e[i].v) != k)
            {
                C[v][0] = F[v][0];
                for (int i = 1; f[v][i - 1]; ++i)
                    C[v][i] = min(C[v][i - 1], C[f[v][i - 1]][i - 1]);
                D3(v, u);
            }
    }
    int main()
    {
        n = R();
        m = R();
        for (int i = 1; i <= n; ++i)
            a[F[i][0].p = F[i][1].p = i] = R();
        for (int i = 1, u, v, w; i < n; ++i)
            u = R(), v = R(), A(u, v, w = R()), A(v, u, w);
        s[1] = a[1];
        D1(d[1] = 1);
        D2(1, 0);
        for (int i = 1; i <= n; ++i)
            F[i][0].y += a[i], F[i][1].y += a[i];
        C[1][0] = F[1][0];
        D3(1, 0);
        for (int i = 0, x, y, u, v, l, k; i < m; ++i)
        {
            Q = {1000000000000000000ll, 0};
            if (d[u = x = R()] < d[v = y = R()])
                swap(x, y);
            while (d[x] > d[y])
                Q = min(Q, C[x][k = __lg(d[x] - d[y])]), x = f[x][k];
            if (x == y)
                Q = min(Q, C[l = x][0]);
            else
            {
                for (k = __lg(d[x]); k >= 0; --k)
                    if (f[x][k] != f[y][k])
                        Q = min({Q, C[x][k], C[y][k]}), x = f[x][k], y = f[y][k];
                Q = min({Q, C[x][0], C[y][0], C[l = f[x][0]][0]});
            }
            P(Q.y + s[u] + s[v] - s[l] - s[f[l][0]]);
            *O++ = '\n';
        }
        fwrite(obuf, O - obuf, 1, stdout);
        return 0;
    }
    
    • 1

    信息

    ID
    8215
    时间
    1000ms
    内存
    512MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者