Processing math: 100%

[USACO12FEB]附近的牛Nearby Cows

题目概述

题目描述

Farmer John has noticed that his cows often move between nearby fields. Taking this into account, he wants to plant enough grass in each of his fields not only for the cows situated initially in that field, but also for cows visiting from nearby fields. Specifically, FJ's farm consists of N fields (1 <= N <= 100,000), where some pairs of fields are connected with bi-directional trails (N-1 of them in total). FJ has designed the farm so that between any two fields i and j, there is a unique path made up of trails connecting between i and j. Field i is home to C(i) cows, although cows sometimes move to a different field by crossing up to K trails (1 <= K <= 20). FJ wants to plant enough grass in each field i to feed the maximum number of cows, M(i), that could possibly end up in that field -- that is, the number of cows that can potentially reach field i by following at most K trails. Given the structure of FJ's farm and the value of C(i) for each field i, please help FJ compute M(i) for every field i.
给你一棵 n 个点的树,点带权,对于每个节点求出距离它不超过 k 的所有节点权值和 mi

输入输出格式

输入格式

* Line 1: Two space-separated integers, N and K. * Lines 2..N: Each line contains two space-separated integers, i and j (1 <= i,j <= N) indicating that fields i and j are directly connected by a trail. * Lines N+1..2N: Line N+i contains the integer C(i). (0 <= C(i) <= 1000)

第一行两个正整数 n,k。 接下来 n1 行,每行两个正整数 u,v,表示 u,v 之间有一条边。

最后 n 行,每行一个非负整数 ci,表示点权。

输出格式

* Lines 1..N: Line i should contain the value of M(i).

输出 n 行,第 i 行一个整数表示 mi

输入输出样例

输入样例 #1
6 2 
5 1 
3 6 
2 4 
2 1 
3 2 
1 
2 
3 
4 
5 
6 
输出样例 #1
15 
21 
16 
10 
8 
11 

数据范围

样例解释
There are 6 fields, with trails connecting (5,1), (3,6), (2,4), (2,1), and (3,2). Field i has C(i) = i cows. Field 1 has M(1) = 15 cows within a distance of 2 trails, etc.

对于 100% 的数据:1n1051k200ci1000

解题报告

题意理解

给你一棵 n 个点的树,点带权,对于每个节点求出距离它不超过 k 的所有节点权值和 mi

算法解析

  1. 树形结构
  2. 统计一定距离的点权和
  3. 树上节点特别多,基本上要线性复杂度
  4. 程序员的第六感

综上所述,我们得知这道题目需要使用,树形DP算法。

然后我们不难设计出,状态表示

f[i][j]ij

因此,我们不难发现,在这个状态表示中,状态转移,只会从儿子节点中转移过来。

利用儿子节点,更新父亲节点。

f[i][j]=f[k][j1]kij11

但是,题目并没有如此简单。

在本题中,对于一个树上节点,他可以被那些节点转移过来呢

  1. 子辈节点(儿子,子树,兄弟的子树)
  2. 同辈节点(兄弟)
  3. 祖辈节点(父亲,祖先)

对于,子辈,同辈,这些节点的转移,显然都是满足,树形DP的自下而上的转移方式。

但是,祖辈节点们,可就是完全违背,我们树形DP的转移方式。

怎么办?

我们不妨,再来一次转移,而且本次转移,自上而下

因此,我们利用父亲节点,更新儿子节点

f[i][j]=f[S][j1]sij1,1

那么这里的

f[S][j1]

我们根据这张图片,分析一波

父亲的转移,让我们的同辈节点,和同辈的儿子节点都累加了。

此时,我们发现

  1. 子辈节点,多。
  2. 同辈节点,刚好
  3. 父辈节点,刚好

我们发现,x的距离为2的点,包含到k距离为1k的儿子们.

而这些点位于k的子树中的点已经在第一次转移,加入到里面去了。

因此,我们不得不,容斥原理,处理多余的子辈节点

推到出来,就是

f[S][j]f[x][j2]Sx,yxj1Sx(j1)1Sy


代码解析

#include <bits/stdc++.h>
using namespace std;
const int N=110000,K=21;
int n,k,a[N],f[N][K],deep[N];
vector<int> g[N];
void dfs(int x,int s)
{
	deep[x]=deep[s]+1;
	for(int y:g[x])
	{
		if (y==s)
			continue;
		dfs(y,x);
		for(int p=1; p<=k; p++)
			f[x][p]+=f[y][p-1];
	}
}
void dfs2(int x)
{
	for(int y:g[x])
	{
		if (deep[y]<=deep[x])
			continue;
		for(int p=k; p>=2; p--)
			f[y][p]-=f[y][p-2];
		for(int p=1; p<=k; p++)
			f[y][p]+=f[x][p-1];
		dfs2(y);
	}
}
inline void init()
{
	scanf("%d%d",&n,&k);
	for(int i=1; i<n; i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		g[a].push_back(b);
		g[b].push_back(a);
	}
	for(int i=1; i<=n; i++)
		scanf("%d",&f[i][0]);
	dfs(1,0);
	dfs2(1);
	for(int i=1; i<=n; i++)
	{
		int ans=0;
		for(int j=0; j<=k; j++)
			ans+=f[i][j];
		printf("%d\n",ans);
	}
}
signed main()
{
	init();
	return 0;
}

本文作者:秦淮岸灯火阑珊

本文链接:https://www.cnblogs.com/gzh-red/p/11844919.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   秦淮岸灯火阑珊  阅读(248)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 上周热点回顾(1.20-1.26)
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起