[树形DP] The 2021 ICPC Asia Nanjing Regional Contest H题

Posted 晁棠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[树形DP] The 2021 ICPC Asia Nanjing Regional Contest H题相关的知识,希望对你有一定的参考价值。

1.https://codeforces.com/gym/103470/problem/H

题意:

在一棵树上的每个节点都有不同数量的蝴蝶。当你进入一个节点时,若那个节点上有蝴蝶,你将会抓住那个节点的蝴蝶,但你会惊动那个节点的子节点里的蝴蝶。你从一个节点到另一个节点,并抓到蝴蝶的时间为1秒,被惊动的蝴蝶将会在 t i ( t i < = 3 ) t_i(t_i<=3) ti(ti<=3)秒后飞走。

从顶点1开始,请问最多可以抓到多少蝴蝶?

题解:

将子树全部分成三种,一种是从子树根节点一直往下做,记为 f ( x ) f(x) f(x);一种是从子树的根节点已经被取走了,但是也从这个点出发一直往下做,记为 g ( x ) g(x) g(x);最后一种是进入一个根节点,但是立刻掉头回到原来的点,再走下一棵树,记为 h ( x ) h(x) h(x)

因此,我们可以得到一下公式 f ( u ) = a u + g ( u ) , h ( u ) = a u + ∑ g ( v ) f(u)=a_u+g(u),h(u)=a_u+\\sumg(v) f(u)=au+g(u)h(u)=au+g(v)

接下来考虑 g u g_u gu如何计算。

第一种情况,当我们从 u u u节点到达一个子节点 v v v之后就一直走下去,其他子节点的蝴蝶就无法抓到,那此时的状态转移方程为 g ( u ) = m a x f ( v i ) + ∑ v j ≠ v i g ( v j ) = m a x a v + ∑ g ( v ) g(u)=max\\f(v_i) + \\sum_v_j\\ne v_ig(v_j)\\=max\\a_v\\+\\sumg(v) g(u)=maxf(vi)+vj=vig(vj)=maxav+g(v)

第二种情况,但我们从 u u u节点到达一个子节点 v v v之后就掉头,去其他子树,这样子状态转移方程为 g ( u ) = m a x f ( v i ) + h ( v j ) + ∑ v i ≠ v j ≠ v k g ( v k ) = m a x a ( v i ) + h ( v j ) + ∑ v j ≠ v k g ( v k ) g(u)=max\\f(v_i)+h(v_j)+\\sum_v_i\\ne v_j \\ne v_k g(v_k)\\=max\\a(v_i)+h(v_j)+\\sum_v_j \\ne v_k g(v_k)\\ g(u)=maxf(vi)+h(vj)+vi=vj=vkg(vk)=maxa(vi)+h(vj)+vj=vkg(vk)。然后这个式子如果要枚举则要 O ( n 2 ) O(n^2) O(n2)的时间复杂度,我们可以再优化,我们的 a ( v i ) a(v_i) a(vi)必然是取最大值,那么就一直取最大值,而 h ( v j ) h(v_j) h(vj)就一直枚举。当枚举到 v i = v j v_i=v_j vi=vj时,我们的 a a a取第二大值即可。也就是说,我们枚举哪个点是只走一步就掉头的点,掉头前往 t = 3 t=3 t=3的存在最多蝴蝶的点,然后再在这个点一路往下跑。

// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm> 
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long

using namespace std;

const int N = 1e5 + 5;
int n, T;
int f[N], g[N], h[N];
int a[N], t[N];

vector<int> ma[N];

void ready()

	IOS;
	cin >> T;


void dfs(int u, int fa) 
	int max1 = 0, max2 = 0, maxa=0;
	int res = 0;
	for (auto v : ma[u]) 
		if (v == fa) continue;
		dfs(v, u);
	
	for (auto v : ma[u]) 
		if (v == fa) continue;
		res += g[v];
		maxa = max(maxa, a[v]);
	
	h[u] = a[u] + res;
	g[u] = maxa + res;
	for (auto v : ma[u]) 
		if (v == fa || t[v] != 3) continue;
		if (a[v] > max1) 
			max2 = max1;
			max1 = a[v];
		
		else 
			max2 = max(max2, a[v]);
		
	
	for (auto v : ma[u]) 
		if (t[v] == 3 && a[v] == max1) 
			g[u] = max(g[u], max2 + h[v] + res - g[v]);
		
		else 
			g[u] = max(g[u], max1 + h[v] + res - g[v]);
		
	
	f[u] = a[u] + g[u];


void work()

	cin >> n;
	ffor(i, 1, n) 
		a[i] = f[i] = g[i] = h[i] = t[i] = 0;
		ma[i].clear();
	
	ffor(i, 1, n) cin >> a[i];
	ffor(i, 1, n) cin >> t[i];
	ffor(i, 1, n - 1) 
		int u; int v;
		cin >> u >> v;
		ma[u].push_back(v);
		ma[v].push_back(u);
	
	dfs(1, 0);以上是关于[树形DP] The 2021 ICPC Asia Nanjing Regional Contest H题的主要内容,如果未能解决你的问题,请参考以下文章