1. 程式人生 > >$bzoj1060-ZJOI2007$ 時態同步 貪心 樹形$dp$

$bzoj1060-ZJOI2007$ 時態同步 貪心 樹形$dp$

lld %d ret can str 包含 要花 個數 urn

  • 題面描述

    • \(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;
}

$bzoj1060-ZJOI2007$ 時態同步 貪心 樹形$dp$