1. 程式人生 > >BZOJ1060:[ZJOI2007]時態同步——題解

BZOJ1060:[ZJOI2007]時態同步——題解

ace zjoi 目前 lan 然而 block tar pan struct

http://www.lydsy.com/JudgeOnline/problem.php?id=1060

https://www.luogu.org/problemnew/show/P1131

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

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

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

題面很長,看完就知道是樹上dp裸題且很簡單。

(然後我就傻了少加了很多東西)

顯然對於給定的一個節點,其子樹上的最晚時間即是最優時間。

所以維護dp[i][0]為i節點往下傳的最晚時間,dp[i][1]為i的子樹用了多少道具。

所以我們有

dp[u][1]+=dp[u][0]-dp[v][0]-w+dp[v][1];

很顯然吧。

(然而請一定提前更新最晚時間,不要邊找最大值邊更新dp1不然你就會像我一樣卡在sb題上。)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while
(!isdigit(ch)){w|=ch==-;ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int to,nxt; ll w; }e[N*2]; int n,rt,cnt,head[N]; ll dp[N][2]; inline void add(int u,int v,ll w){ e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt; } void dfs(int u,int f){ for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to;ll w=e[i].w; if(v==f)continue; dfs(v,u); dp[u][0]=max(dp[u][0],dp[v][0]+w); } for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to;ll w=e[i].w; if(v==f)continue; dp[u][1]+=dp[u][0]-dp[v][0]-w+dp[v][1]; } } int main(){ n=read();rt=read(); for(int i=1;i<n;i++){ int u=read(),v=read(),w=read(); add(u,v,w);add(v,u,w); } dfs(rt,0); printf("%lld\n",dp[rt][1]); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ1060:[ZJOI2007]時態同步——題解