樹上前綴和練手題:WA2

---恢復內容開始---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); 
}

打死白學家

---恢復內容結束---

相關文章
相關標籤/搜索