树上前缀和练手题:WA2

---恢复内容开始---

之前做了个运输计划,发现了树上前缀和这个神奇的东西

因为树这个特殊的结构,所以如果树是静态的,那么区间问题树上前缀和很好用。

提一下,如果是离线的树上修改,树上差分也是一个很好用的东西。

(实际上是我不会打树剖)

然后今天做了个这个题:

 山山最近开始玩一款叫做《白色相簿 2》的 Galgame。众所周知,Galgame 的剧情可以
用一棵树来表示,其中非叶节点表示选项分支,叶子表示结局,树边表示支线剧情,剧情从
树根开始向叶子方向进行。看完一段支线剧情所花的时间是一定的。
 《白色相簿 2》共有 n 个选项分支或结局,有 n - 1 段支线剧情,其中根节点被编号
为 1 号。因为山山非常心急,于是他把自己的存档功能搞崩了。
 山山现在只能在固定的 k 个选项前存档,每次观看剧情需要从存档处开始。他想花最少
的时间看一遍所有的剧情。 但是他现在有一个赛艇比赛要看,于是他希望你能帮他计算出
这个最少时间。

于是我一看,这个题不就是静态的去弄树上的区间问题吗?一条链上的和,树上前缀和很好用耶

于是打了个树上前缀和。

爆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); 
}

打死白学家

---恢复内容结束---

转载于:https://www.cnblogs.com/euphoria-eden/p/7677050.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值