$bzoj1060-ZJOI2007$ 时态同步 贪心 树形$dp$

  • 题面描述

    • \(Q\)在电子工艺实习课上学习焊接电路板。一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字\(1,2,3….\)进行标号。电路板的各个节点由若干不相交的导线相连接,且对于电路板的任何两个节点,都存在且仅存在一条通路(通路指连接两个元件的导线序列)。在电路板上存在一个特殊的元件称为“激发器”。当激发器工作后,产生一个激励电流,通过导线传向每一个它所连接的节点。而中间节点接收到激励电流后,得到信息,并将该激励电流传向与它连接并且尚未接收到激励电流的节点。最终,激烈电流将到达一些“终止节点”——接收激励电流之后不再转发的节点。激励电流在导线上的传播是需要花费时间的,对于每条边\(e\),激励电流通过它需要的时间为\(t_e\),而节点接收到激励电流后的转发可以认为是在瞬间完成的。现在这块电路板要求每一个“终止节点”同时得到激励电路——即保持时态同步。由于当前的构造并不符合时态同步的要求,故需要通过改变连接线的构造。目前小\(Q\)有一个道具,使用一次该道具,可以使得激励电流通过某条连接导线的时间增加一个单位。请问小\(Q\)最少使用多少次道具才可使得所有的“终止节点”时态同步?
  • 输入格式

    • 第一行包含一个正整数\(N\),表示电路板中节点的个数。
    • 第二行包含一个整数\(S\),为该电路板的激发器的编号。
    • 接下来\(N-1\)行,每行三个整数\(a , b , t\)。表示该条导线连接节点\(a\)与节点\(b\),且激励电流通过这条导线需要\(t\)个单位时间
  • 输出格式

    • 仅包含一个整数\(V\),为小\(Q\)最少使用的道具次数。
  • 题解

    • 第一次看这题时看错题,看成了\(APIO2016烟火表演\),然后就列出了\(f_{u,t}=\sum_{vsm_u}min_{t'\leq t}(f_{v,t'}+t-t')\)
    • 然后再看题才发现只能增加边权,不能减少边权,再看一眼刚列出的式子\(f_{u,t}=\sum_{vsm_u}min_{t'\leq t}(f_{v,t'}+t-t')\\\Rightarrow f_{u,t}=\sum_{vsm_u}mn_{v,t}+t\ (mn_{v,t}=min_{t'\leq t}f_{v,t'}-t')\)
    • \(f_v\)单调不减,\(mn_{v,t}\)固定,\(f_u\)随 t 增长而变大,而对于叶子,\(f_{leaf,t}\)单增。
    • 由数学归纳法可知,\(f_u​\)单调增。
    • 因此这个dp方程存在理论下界,即刚好满足条件\((t_u=max\ t_v+w_{v\to u})\)时最小。
    • 因此此题我们可以贪心,记录\(t_u​\)表示想要让叶子都同态至少多少时间,\(f_u​\)表示使叶子同步到\(t_u​\)这个时间最少花费。
    • 递推即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=5e5+5;
const int MAXM=1e6+6;
int n,S;
int edge,head[MAXN],tail[MAXM],nex[MAXM],w[MAXM];
ll f[MAXN],g[MAXN];
void add(int u,int v,int W){
    edge++,nex[edge]=head[u],head[u]=edge,tail[edge]=v,w[edge]=W;
}
void dfs(int u,int p){
    for (int e=head[u];e;e=nex[e]){
        int v=tail[e];
        if (v==p) continue;
        dfs(v,u);
        g[u]=max(g[u],g[v]+w[e]);
    }
    for (int e=head[u];e;e=nex[e]){
        int v=tail[e];
        if (v==p) continue;
        f[u]+=f[v]+g[u]-(g[v]+w[e]);
    }
}
int main(){
    scanf("%d%d",&n,&S);
    for (int i=1;i<n;i++){
        int u,v,w; scanf("%d%d%d",&u,&v,&w);
        add(u,v,w); add(v,u,w);
    }
    dfs(S,0);
    printf("%lld\n",f[S]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/shjrd-dlb/p/10803861.html
今日推荐