---恢復內容開始---spa
以前作了個運輸計劃,發現了樹上前綴和這個神奇的東西code
由於樹這個特殊的結構,因此若是樹是靜態的,那麼區間問題樹上前綴和很好用。blog
提一下,若是是離線的樹上修改,樹上差分也是一個很好用的東西。it
(其實是我不會打樹剖)io
而後今天作了個這個題:class
山山最近開始玩一款叫作《白色相簿 2》的 Galgame。衆所周知,Galgame 的劇情能夠
用一棵樹來表示,其中非葉節點表示選項分支,葉子表示結局,樹邊表示支線劇情,劇情從
樹根開始向葉子方向進行。看完一段支線劇情所花的時間是必定的。
《白色相簿 2》共有 n 個選項分支或結局,有 n - 1 段支線劇情,其中根節點被編號
爲 1 號。由於山山很是心急,因而他把本身的存檔功能搞崩了。
山山如今只能在固定的 k 個選項前存檔,每次觀看劇情須要從存檔處開始。他想花最少
的時間看一遍全部的劇情。 可是他如今有一個賽艇比賽要看,因而他但願你能幫他計算出
這個最少時間。next
因而我一看,這個題不就是靜態的去弄樹上的區間問題嗎?一條鏈上的和,樹上前綴和很好用耶di
因而打了個樹上前綴和。時間
爆int了50分,改爲longlong就A了比賽
其實正解並不須要樹上前綴和,可是以爲樹上前綴和對於這個題很好用……之類的
總之練了個手。
#include <stdio.h> #define MAXN ((int)(1e5)+10) #define add(ss, ee, vv) do { \ E[++cnt].e = ee; E[cnt].v = vv; \ E[cnt].next = G[ss]; \ G[ss] = cnt; \ } while(0) struct edge { int e, v, next; } E[MAXN]; int cnt; int G[MAXN]; int sum[MAXN]; long long int ans; bool can[MAXN]; bool leaf[MAXN]; void init(int now) { if(G[now] == 0) { leaf[now] = true; return; } for(int i = G[now]; i != 0; i = E[i].next) { sum[E[i].e] = sum[now]+E[i].v; init(E[i].e); } } void dfs(int now, int save) { for(int i = G[now]; i != 0; i = E[i].next) { if(can[E[i].e]) { ans += (long long int)(sum[E[i].e]-sum[save]); dfs(E[i].e, E[i].e); } else if(leaf[E[i].e]) ans += (long long int)(sum[E[i].e]-sum[save]); else dfs(E[i].e, save); } } int main() { freopen("wa2.in", "r", stdin); freopen("wa2.out", "w", stdout); int i, p, sss, eee, vvv, N, K; scanf("%d%d", &N, &K); for(i = 1; i <= K; i++) { scanf("%d", &p); can[p] = true; } for(i = 1; i <= N-1; i++) { scanf("%d%d%d", &sss, &eee, &vvv); add(sss, eee, vvv); } init(1); dfs(1, 1); printf("%lld\n", ans); }
打死白學家
---恢復內容結束---