树上前缀和练手题:WA2
Posted 全宇宙唯一指定最菜的菜鸡的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树上前缀和练手题: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); }
打死白学家
---恢复内容结束---
以上是关于树上前缀和练手题:WA2的主要内容,如果未能解决你的问题,请参考以下文章