【洛谷P1131】[ZJOI2007]時態同步
題目描述
小Q在電子工藝實習課上學習焊接電路板。一塊電路板由若幹個元件組成,我們不妨稱之為節點,並將其用數字1,2,3….進行標號。電路板的各個節點由若幹不相交的導線相連接,且對於電路板的任何兩個節點,都存在且僅存在一條通路(通路指連接兩個元件的導線序列)。
在電路板上存在一個特殊的元件稱為“激發器”。當激發器工作後,產生一個激勵電流,通過導線傳向每一個它所連接的節點。而中間節點接收到激勵電流後,得到信息,並將該激勵電流傳向與它連接並且尚未接收到激勵電流的節點。最終,激烈電流將到達一些“終止節點”――接收激勵電流之後不再轉發的節點。
激勵電流在導線上的傳播是需要花費時間的,對於每條邊e,激勵電流通過它需要的時間為te,而節點接收到激勵電流後的轉發可以認為是在瞬間完成的。現在這塊電路板要求每一個“終止節點”同時得到激勵電路――即保持時態同步。由於當前的構造並不符合時態同步的要求,故需要通過改變連接線的構造。目前小Q有一個道具,使用一次該道具,可以使得激勵電流通過某條連接導線的時間增加一個單位。請問小Q最少使用多少次道具才可使得所有的“終止節點”時態同步?
輸入輸出格式
輸入格式:
第一行包含一個正整數N,表示電路板中節點的個數。
第二行包含一個整數S,為該電路板的激發器的編號。
接下來N-1行,每行三個整數a , b , t。表示該條導線連接節點a與節點b,且激勵電流通過這條導線需要t個單位時間。
輸出格式:
僅包含一個整數V,為小Q最少使用的道具次數。
輸入輸出樣例
輸入樣例#1: 復制3 1 1 2 1 1 3 3輸出樣例#1: 復制
2
說明
對於40%的數據,N ≤ 1000
對於100%的數據,N ≤ 500000
對於所有的數據,te ≤ 1000000
分析
這是一個很巧妙的題,說是樹形動規,但是我覺的更像一個樹上的dfs。先與處理每個節點到葉子節點的最大距離,在同一個分支中,所有節點的值必須相同,所以找出最大的那一個,把其他的的都加到這麽多。
代碼
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=500006; inline void read(int &x){ x=0; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} } int n,s,tot,head[maxn]; ll ans,dis[maxn]; struct node{ int next,to,dist; }e[maxn<<1]; inline void ins(int from,int to,int dist){ e[++tot].next=head[from]; e[tot].to=to; e[tot].dist=dist; head[from]=tot; } void dfs(int x,int fa){ for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa){ dfs(e[i].to,x); dis[x]=max(dis[x],dis[e[i].to]+e[i].dist); } } void dp(int x,int fa){ for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa){ dp(e[i].to,x); ans+=dis[x]-dis[e[i].to]-e[i].dist; } } int main(){ read(n);read(s); for(int i=1;i<n;++i){ int a,b,t; read(a);read(b);read(t); ins(a,b,t); ins(b,a,t); } dfs(s,-1); dp(s,-1); printf("%lld",ans); return 0; }
【洛谷P1131】[ZJOI2007]時態同步