1. 程式人生 > >[ZJOI2007]時態同步(dfs+貪心)

[ZJOI2007]時態同步(dfs+貪心)

ostream 同時 一個 != n) htm code zjoi2007 zjoi

Q在電子工藝實習課上學習焊接電路板。一塊電路板由若幹個元件組成,我們不妨稱之為節點,並將其用數字1,2,3.進行標號。電路板的各個節點由若幹不相交的導線相連接,且對於電路板的任何兩個節點,都存在且僅存在一條通路(通路指連接兩個元件的導線序列)。

在電路板上存在一個特殊的元件稱為“激發器”。當激發器工作後,產生一個激勵電流,通過導線傳向每一個它所連接的節點。而中間節點接收到激勵電流後,得到信息,並將該激勵電流傳向與它連接並且尚未接收到激勵電流的節點。最終,激烈電流將到達一些“終止節點”――接收激勵電流之後不再轉發的節點。

激勵電流在導線上的傳播是需要花費時間的,對於每條邊e,激勵電流通過它需要的時間為t?,而節點接收到激勵電流後的轉發可以認為是在瞬間完成的。現在這塊電路板要求每一個“終止節點”同時得到激勵電路――即保持時態同步。由於當前的構造並不符合時態同步的要求,故需要通過改變連接線的構造。目前小QQ有一個道具,使用一次該道具,可以使得激勵電流通過某條連接導線的時間增加一個單位。請問小Q最少使用多少次道具才可使得所有的“終止節點”時態同步?

Solution

這題可以直接一遍dfs做,

我們對於一個節點,先遍歷它的所有子樹,從中貪心的找出到達葉子的最遠距離,並把這個作為局部最優解。

然後我們把其他所有子樹全部調整為那樣的距離,再向上回溯。

Code

#include<iostream>
#include<cstdio>
using namespace std;
int head[500009],tot,n,s,x,y;
long long z,ans;
struct efe
{
    int n,to;
    long long l;
}an[1000009];
void add(int u,int v,long long
l) { an[++tot].n=head[u]; an[tot].to=v; an[tot].l=l; head[u]=tot; } long long dfs(int u,int fa) { long long ma=0; for(int i=head[u];i;i=an[i].n) if(an[i].to!=fa)an[i].l+=dfs(an[i].to,u); for(int i=head[u];i;i=an[i].n) if(an[i].to!=fa)ma=max(ma,an[i].l);
for(int i=head[u];i;i=an[i].n) if(an[i].to!=fa)ans+=ma-an[i].l; return ma; } int main() { cin>>n>>s; for(int i=1;i<n;++i) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); dfs(s,0); cout<<ans; return 0; }

[ZJOI2007]時態同步(dfs+貪心)