[ZJOI12007] 时态同步


[ZJOI12007] 时态同步

[ZJOI2007] 时态同步 – 洛谷

将图看成以激发器 /(S/) 为根的一棵树。

容易发现,所有终止节点均为叶子节点,于是题意转化为:至少改动多少次边权使得 “时态同步”。

设 /(u, v/) 为两个不同的叶子节点。

那么,若 /(u,v/) 时态同步,则在以 /(lca(u,v)/) 为根的子树中,从 /(lca(u,v)/) 到 /(u,v/) 的时态也同步。这是因为在 /(lca(u,v)/) 以上 /(u,v/) 到 /(S/) 的路径就重叠了。

如上,可知若在以 /(S/) 为根的树中时态同步,则在其任意一棵子树中,时态必定也同步。

考虑树形 /(DP/) :

设 /(F(x)/) 表示使以 /(x/) 为根的子树时态同步所需的最小次数。

/(path(x)/) 表示时态同步时,从 /(x/) 到叶子节点的路径长度。

再设 /(MaxPath/) 表示未经操作时,/(x/) 到叶子节点的最长路径。

容易得出转移方程:

/[F(x)=/sum_{son/in x}{F(son)}+/sum_{son/in x}{MaxPath-path(son)-edge(x,son)}
/]

完美解决。

#include <bits/stdc++.h>
#define rep(var, st, ed) for(int var = st; var <= ed; var++)
#define fin freopen("in", "r", stdin)
#define fout freopen("out", "w", stdout)
namespace IO{
    template <typename T>
    inline void read(T &x)
    {
        x = 0;
        T w = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') { if (ch == '-') w = -1;ch = getchar();}
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - 48, ch = getchar();
        x = x * w;
    }
    template <typename T, typename... Args>
    inline void read(T &x, Args&... args) {read(x);read(args...);}
};
using IO::read;
using LL = long long;
const int N = 500010;
int n, s;
LL f[N], path[N];
struct Node {
    int id;
    LL cost;
}; std::vector<Node> G[N];
void dp(int x, int fa)
{
    LL Max = 0;
    for (auto son : G[x])
    {
        if (son.id == fa) continue;
        dp(son.id, x);
        f[x] += f[son.id], Max = std::max(Max, path[son.id] + son.cost);
    }
    path[x] = Max;
    for (auto son : G[x])
        if (son.id != fa) f[x] += Max - path[son.id] - son.cost;
}
int main()
{
    read(n, s);
    rep(i, 1, n - 1)
    {
        int u, v; LL t;
        read(u, v, t);
        G[u].push_back((Node){v, t});
        G[v].push_back((Node){u, t});
    }
    dp(s, 0);
    printf("%lld/n", f[s]);
    return 0;
}

原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/277558.html

(0)
上一篇 2022年7月28日
下一篇 2022年7月28日

相关推荐

发表回复

登录后才能评论