\(c\) 國擁有一張四通八達的高速公路網樹,其中有 \(n\) 個城市,城市之間由一共 \(n-1\) 條高速公路連線。除了首都 \(1\) 號城市,每個城市都有一家本地的客運公司,可以發車前往全國各地,有若干條高速公路連向其他城市,這是乙個樹型結構,\(1\) 號城市(首都)為根。假設有乙個人要從 \(i\) 號城市坐車出發前往 \(j\) 號城市,那麼他要花費 \(p_i\)*(\(i\) 城市到 \(j\) 城市的距離)\(+q_i\) 元。由於距離首都越遠,國家的監管就越鬆,所以距離首都越遠,客運公司的 \(p_i\)(單位距離**)越大,形式化的說,如果把高速路網看成一棵以首都為根的有根樹,\(i\) 號城市是 \(j\) 號城市的某個祖先,那麼一定存在 \(p_i\le p_j\)。
大寧成為了國家統計局的調查人員,他需要對現在的高速路網進行一次調查,了解從其他每乙個城市到達首都1號城市所花費的金錢(路徑必須是簡單路徑)。
因為有非常多轉車(或不轉車)的抵達首都的方法,所以人工計算這個結果是十分複雜的。大寧非常的懶,所以請你編寫乙個程式解決它。
第 \(1\) 行包含 \(1\) 個非負整數 \(n\),表示城市的個數。
第 \(2\) 到 \(n\) 行,每行描述乙個除首都之外的城市。其中第 \(i\) 行包含 \(4\) 個非負整數 \(f_i,s_i,p_i,q_i\),分別表示 \(i\) 號城市的父親城市,它到父親城市高速公路的長度,以及乘車**的兩個引數。
輸出包含 \(n-1\) 行,每行包含乙個整數。
其中第 \(i\) 行表示從 \(i+1\) 號城市 出發,到達首都最少的乘車費用。
6
1 9 3 0
1 17 1 9
1 1 1 6
4 13 2 15
4 9 2 4
27267
4324
對於前 \(40\%\) 的資料 \(1\le n\le1000\)。
對於另外 \(20\%\) 的資料 滿足從第 \(i\)(\(i\neq1\))個城市出發的高速公路連向第 \(i-1\) 個城市。
對於所有的資料 \(1\le n\le1000000,0\le p_i,q_i\le2^–1\),保證結果不會大於 \(2^–1\)。
\(dp\),斜率優化
看看這個題目,其實一下子就能想到我們可以在每一條從根節點到葉子節點的路徑上線性 \(dp\) 。
那麼方程也異常簡單:設 \(f[i]\) 為從 \(i\) 點到達根節點所需最小費用,\(pre_i\) 為 \(i\) 到根節點路徑上所有點的集合,\(lj[i]\) 為 \(i\) 到根節點的距離,那麼自然有:
\[ f[i]=min_(f[j]+(lj[i]-lj[j])*p[i]+q[i]) \]
當然,這個 \(dp\) 方程的複雜度是不過關的。按照一貫的套路,這種很容易想式子的 \(dp\) 題總滿足決策單調性。所以我們嘗試一下列出它的決策之間有什麼關係。
設 \(i\) 的兩個決策點為 \(j,k\) ,其中 \(j\in pre_k\) ,\(j,k\in pre_i\) 。
如果從點 \(k\) 轉移比從點 \(j\) 轉移更優,那麼自然有:
\[ f[k]+(lj[i]-lj[k])*p[i]+q[i]
我們發現,由於題目有 \(p_i>p_\) 的條件,那麼當我們在一條鏈上 \(dp\) 時,一旦從某一點開始滿足上式,則這個點的子樹內所有點一直都會滿足上式。換句話說,對於這個點的子樹內所有點而言,從 \(k\) 轉移總會比從 \(j\) 轉移更優。
換而言之,此題滿足決策單調性中的斜率優化的條件。
那麼由於 \(p[i]\) 遞增,我們只需要維護乙個斜率單調遞增的決策點佇列即可。
但是這是一棵樹,怎麼辦?
很簡單,每個點在更改決策點的單調佇列時只有三個操作:
那麼我們發現,每到乙個新的點,其實我們只是修改了一下 \(head\) 和 \(tail\) 的值,並修改了佇列中的乙個元素。則我們只需要記住修改之前的那個元素的值,修改之前的隊首對尾的位置即可,當我們退出當前點的時候,只需要照著之前記錄的值改回去就好了!
但是對於這題還不夠。
一般而言,我們的斜率優化總會是 \(o(n)\) 的,因為每個點最多隻會被入隊出隊一次,所以總體複雜度只會取決於決策點個數而不是列舉決策點。
但是在這題裡,乙個決策點可能在這個點裡入隊,在下乙個點裡出隊,而回溯回來的時候又再次入隊,因而不符合每個點最多隻會入隊出隊一次的規則!,換句話說,這樣做的話,複雜度是錯誤的。
那接下來又怎麼做呢?
由於我們的決策點佇列裡,相鄰兩點之間的斜率是單調的,所以我們完全可以通過二分來找到應該 \(++head,--tail\) 所達到的位置!
只需要找到最左邊的,不滿足斜率不等式的位置,以及最右邊的,不滿足斜率單調遞增的位置即可。
當然,二分可能有點小細節,可以看看我的**。(良心注釋)
#include#includeusing namespace std;
int n;
int cntr,head[1000001],to[1000001],nx[1000001],w[1000001];
int q[1000001];
int que[1000001],h,t;
long long p[1000001],lj[1000001],f[1000001];
void addr(int u,int v,int w)
double slope(int a,int b)//斜率不等式
void dp(int x)
h=ans,p=que[h];
f[x]=f[p]+(lj[x]-lj[p])*p[x]+q[x];
l=h,r=t-1,ans=t;//這裡的理由與隊首差不多,都是為了結果正確性
while(l<=r)
t=ans;
tpw=que[++t],que[t]=x;//記錄即將被更改的位置的元素並更新
for(int i=head[x];i;i=nx[i])
que[t]=tpw;
h=tph,t=tpt;//修改回進入這個點之前的狀態
}int main()
t=-1;//最開始佇列是空的,所以 tail=head-1
dp(1);
for(int i=2;i<=n;i++)
printf("%lld\n",f[i]);
}
posted @
2019-05-20 20:12
洛水·錦依衛 閱讀(
...)
編輯收藏
luogu P3994 高速公路
逃了物理競賽,機房就2 22人。有一棵樹,其中第i ii個點到第j jj個點的貢獻為dis i,j pi q idis i,j p i q i dis i,j p i q i 若i ii是j jj的祖先,則保證pi pj p i p j pi pj 顯然是乙個在樹上維護的斜率優化的dpdp dp。對...
ccf 高速公路
問題描述 某國有n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由於經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。現在,大臣們幫國王擬了乙個修高速公路的計畫。看了計畫後,國王發現,有些城市之間可以通過高速公路直接 不經過其他城市 或間接 經過乙個或多個其...
201509 4 高速公路
鄰接表存圖 include include include define maxn 200010 using namespace std int dfn maxn low maxn int clock,top 當前元素是被訪問的序號,模擬棧的首部 bool instack maxn intstack...