题解 P3047 [USACO12FEB]附近的牛Nearby Cows
Posted yuanqiqhfz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P3047 [USACO12FEB]附近的牛Nearby Cows相关的知识,希望对你有一定的参考价值。
题解 P3047 [USACO12FEB]附近的牛Nearby Cows
题目大意是给你一颗树,对于每一个节点i,求出范围k之内的点权之和
看数据范围就知道暴力肯定是会t飞的,所以我们要考虑如何dp(代码习惯写dfs)
仔细思考一下我们发现点i走k步能到达的点分为以下两种
1.在i的子树中(由i点往下)
2.经过i的父亲(由i点往上)
这样的问题一般可以用两次dfs解决
我们定义状态f[i][j]表示i点往下j步范围内的点权之和,d[i][j]表示i点往上和往下走j步范围内点权之和。
第一次dfs我们求出所有的f[n][k],这个比较简单,对于节点u和其儿子v,f[u][k] += f[v][j - 1]就行了。(第一次dfs已知叶子节点推父亲节点)
第二次dfs我们通过已经求出的f数组推d数组,对于u和u的儿子v, d[v][k] += (d[u][k - 1] - f[v][k - 2]), 注意数组下表不要越界。d[i][j]的初始值应该赋为f[i][j],因为根节点的d[i][j]就是f[i][j]。(第二次dfs已知父亲节点推儿子节点)
思路说得可能有点罗嗦看代码吧:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
#define N 100005
using namespace std;
inline int read()
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') if (c == '-') f = -1; c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0'; c = getchar();
return x * f;
ll f[N][25], d[N][25];
//f数组和d数组前面已经说了
int val[N];
int n, k, tot, head[N];
struct edge
int to, next;
edge()
edge(int x, int y) to = x; next = y;
a[N * 2];
//邻接表存图
void add(int from, int to)
a[++tot] = edge(to, head[from]);
head[from] = tot;
void dfs(int x, int fa)
for (int i = 0; i <= k; i++) f[x][i] = val[x];
for (int i = head[x]; i; i = a[i].next)
int u = a[i].to;
if (u != fa)
dfs(u, x);//先dfs到叶子节点,然后推父亲节点
for (int i = 1; i <= k; i++)
f[x][i] += f[u][i - 1];
//第一次dfs
void dfs2(int x, int fa)
for (int i = head[x]; i; i = a[i].next)
int u = a[i].to;
if (u != fa)
d[u][1] += f[x][0];
for (int i = 2; i <= k; i++)
d[u][i] += d[x][i - 1] - f[u][i - 2];
dfs2(u, x);//先dfs父亲节点,更新完儿子后dfs儿子
//第二次dfs
int main()
n = read(), k = read();
for (int i = 1; i < n; i++)
int a1 = read(), a2 = read();
add(a1, a2);
add(a2, a1);
for (int i = 1; i <= n; i++)
val[i] = read();
dfs(1, 1);
for (int i = 1; i <= n; i++)
for (int j = 0; j <= k; j++)
d[i][j] = f[i][j];//把f赋给d
dfs2(1, 1);
for (int i = 1; i <= n; i++)
cout << d[i][k] << endl;//输出答案
return 0;
总之有一类树上dp的题,每个节点的答案与这个节点的父亲和儿子都有关,这时候我们可以分两次dfs求出答案,一般这两次dfs便利顺序不同。这要求大家对树的遍历有非常深的理解和实现能力,但是思路其实并没有那么难。
19.08.31
以上是关于题解 P3047 [USACO12FEB]附近的牛Nearby Cows的主要内容,如果未能解决你的问题,请参考以下文章
P3047 [USACO12FEB]附近的牛Nearby Cows
P3047 [USACO12FEB]附近的牛Nearby Cows 树形dp
洛谷P3047 [USACO12FEB]Nearby Cows(树形dp)
bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序