1. 程式人生 > >[ZJOI2007]時態同步

[ZJOI2007]時態同步

edge num names logs cstring 一個 stream 電路板 數字

題目描述

小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就能出來,復雜度O(n)

當時以為此題有坑還去看了題解,事實證明不要把題想難了

對於一個節點x,找到距離最遠的終點,將其他子節點補齊即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long lol;
 7 struct Node
 8 {
 9     int next,to;
10     lol dis;
11 }edge[1000001];
12 int head[500001],num;
13 lol dis[500001],ans;
14 int n,s; 15 void add(int u,int v,int d) 16 { 17 num++; 18 edge[num].next=head[u]; 19 head[u]=num; 20 edge[num].to=v; 21 edge[num].dis=d; 22 } 23 void dfs(int x,int fa) 24 {int i; 25 for (i=head[x];i;i=edge[i].next) 26 { 27 int v=edge[i].to; 28 if (v==fa) continue; 29 dfs(v,x); 30 dis[x]=max(dis[x],dis[v]+edge[i].dis); 31 } 32 for (i=head[x];i;i=edge[i].next) 33 {int v=edge[i].to; 34 if (v==fa) continue; 35 if (dis[v]+edge[i].dis<dis[x]) 36 ans+=dis[x]-dis[v]-edge[i].dis; 37 } 38 } 39 int main() 40 {int i,x,y; 41 lol d; 42 cin>>n; 43 cin>>s; 44 for (i=1;i<=n-1;i++) 45 { 46 scanf("%d%d%lld",&x,&y,&d); 47 add(x,y,d); 48 add(y,x,d); 49 } 50 dfs(s,0); 51 cout<<ans; 52 }

[ZJOI2007]時態同步