[bzoj3829][Poi2014]FarmCraft_树形dp

FarmCraft

题目链接https://lydsy.com/JudgeOnline/problem.php?id=3829

数据范围:略。



题解

因为每条边只能必须走两次,所以我们的路径一定是进入了一棵子树然后出来,不可能再进去。

我们根据这个性质,设计出状态$f_i$表示以$i$为根的子树答案即可。

转移时,我们发现需要对儿子进行一个排序,我们就暴力的判断一下哪个儿子在前面更优即可。

代码

#include <bits/stdc++.h>

#define N 1000010 

using namespace std;

char *p1, *p2, buf[100000];

#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )

int rd() {
	int x = 0, f = 1;
	char c = nc();
	while (c < 48) {
		if (c == ‘-‘)
			f = -1;
		c = nc();
	}
	while (c > 47) {
		x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
	}
	return x * f;
}

int head[N], to[N << 1], nxt[N << 1], tot;

inline void add(int x, int y) {
	to[ ++ tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}

int sz[N];

void dfs(int p, int fa) {
	sz[p] = 1;
	for (int i = head[p]; i; i = nxt[i]) {
		if (to[i] != fa) {
			dfs(to[i], p);
			sz[p] += sz[to[i]];
		}
	}
}

int t[N], f[N];

struct Node {
	int val, id;
}q[N];

// inline bool cmp(const Node &a, const Node &b) {
// 	return a.val < b.val;
// }

inline bool cmp(const Node &a, const Node &b) {
	return max(a.val, sz[a.id] * 2 + b.val) < max(b.val, sz[b.id] * 2 + a.val);
}

void dfs1(int p, int fa) {
	f[p] = t[p];
	for (int i = head[p]; i; i = nxt[i]) {
		if (to[i] != fa) {
			dfs1(to[i], p);
		}
	}
	int cnt = 0;
	for (int i = head[p]; i; i = nxt[i]) {
		if (to[i] != fa) {
			q[ ++ cnt] = (Node) {f[to[i]], to[i]};
		}
	}
	sort(q + 1, q + cnt + 1, cmp);
	int sum = 0;
	for (int i = 1; i <= cnt; i ++ ) {
		f[p] = max(f[p], f[q[i].id] + sum + 1);
		sum += sz[q[i].id] * 2;
	}
}

int main() {
	int n = rd();
	// int m = t[1];
	for (int i = 1; i <= n; i ++ ) {
		t[i] = rd();
	}
	// t[1] = 0;
	for (int i = 1; i < n; i ++ ) {
		int x = rd(), y = rd();
		add(x, y), add(y, x);
	}
	dfs(1, 1);
	dfs1(1, 1);
	// for (int i = 1; i <= n; i ++ ) {
	// 	printf("%d ", f[i]);
	// }
	// puts("");
	cout << max(f[1], (n - 1) * 2 + t[1]) << endl ;
	return 0;
}

原文地址:https://www.cnblogs.com/ShuraK/p/11773693.html

时间: 2024-10-10 08:12:49

[bzoj3829][Poi2014]FarmCraft_树形dp的相关文章

【bzoj3522】[Poi2014]Hotel 树形dp

题目描述 有一个树形结构的宾馆,n个房间,n-1条无向边,每条边的长度相同,任意两个房间可以相互到达.吉丽要给他的三个妹子各开(一个)房(间).三个妹子住的房间要互不相同(否则要打起来了),为了让吉丽满意,你需要让三个房间两两距离相同.有多少种方案能让吉丽满意? 输入 第一行一个数n.接下来n-1行,每行两个数x,y,表示x和y之间有一条边相连. 输出 让吉丽满意的方案数. 样例输入 7 1 2 5 7 2 5 2 3 5 6 4 5 样例输出 5 题解 树形dp 如果树上三个点之间两两距离相同

3522: [Poi2014]Hotel( 树形dp )

枚举中点x( 即选出的三个点 a , b , c 满足 dist( x , a ) = dist( x , b ) = dist( x , c ) ) , 然后以 x 为 root 做 dfs , 显然两个位于 x 的同一颗子树内的点是不可能被同时选到的 . 我们对 x 的每一颗子树进行 dfs , 记录下当前子树中的点到 x 距离为 d ( 1 <= d <= n ) 有多少个 , 记为 cnt[ 0 ][ i ] . 然后 cnt[ 1 ][ i ] 记录之前 dfs 过的子树的 cnt[

BZOJ 3829 Poi2014 FarmCraft 树形DP+贪心

题目大意:给定一棵树,从1号节点出发对树进行欧拉遍历,每到达一个点这个点就开始装MC,每个点装MC的时间不同,最后回到1号节点装MC,求所有人都能联机的最少时间 令f[x]为对第x个节点进行欧拉遍历的时间,g[x]为对第x个节点进行欧拉遍历并完成所有节点的装机的最小时间 那么在每个节点以什么顺序遍历每棵子树呢? 我们发现装机多出来的时间 即g[x]-f[x]可以用来遍历其它子树 那么显然要从g[x]-f[x]大的子树开始遍历 因此对每个节点的子树按照g[x]-f[x]递减排个序即可 时间复杂度O

【BZOJ3522】【BZOJ4543】【POI2014】Hotel 树形DP 长链剖分 启发式合并

题目大意 ? 给你一棵树,求有多少个组点满足\(x\neq y,x\neq z,y\neq z,dist_{x,y}=dist_{x,z}=dist_{y,z}\) ? \(1\leq n\leq 100000\) 题解 ? 问题转换为有多少个组点满足\(dist_{i,x}=dist_{i,y}=dist_{i,z}\) ? 我们考虑树形DP ? \(f_{i,j}=\)以\(i\)为根的子树中与\(i\)的距离为\(j\)的节点数 ? \(g_{i,j}=\)以\(i\)为根的子树外选择一个

树形DP水题系列(1):FAR-FarmCraft [POI2014][luogu P3574]

题目 大意: 边权为1 使遍历树时到每个节点的时间加上点权的最大值最小 求这个最小的最大值 思路: 最优化问题 一眼树形DP 考虑状态设立 先直接以答案为状态 dp[u] 为遍历完以u为根的子树的答案 再考虑状态转移 dp[u]=MAX(dp[to]+1,siz+dp[to]);siz为枚举子树到以to为节点的子树时之前已遍历的总时间 很明显这个转移过来的dp值的最优化依赖于子树遍历的顺序 所以我们需要找到一种最优的子树遍历顺序来使每个子树得到最优的dp值来更新 我们通过观察可以发现 交换任意两

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi

HDU 1520 树形dp裸题

1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using nam

HDU2196 Computer(树形DP)

和LightOJ1257一样,之前我用了树分治写了.其实原来这题是道经典的树形DP,感觉这个DP不简单.. dp[0][u]表示以u为根的子树中的结点与u的最远距离 dp[1][u]表示以u为根的子树中的结点与u的次远距离 这两个可以一遍dfs通过儿子结点转移得到.显然dp[0][u]就是u的一个可能的答案,即u往下走的最远距离,还缺一部分就是u往上走的最远距离: dp[2][u]表示u往上走的最远距离 对于这个的转移,分两种情况,是这样的: dp[2][v] = max( dp[0][u]+w