[树形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题的主要内容,如果未能解决你的问题,请参考以下文章

The 2021 ICPC Asia Shenyang Regional Contest补题

ICPC 2021网络赛2The 2021 ICPC Asia Regionals Online Contest (II)签到题5题

2021ICPC网络赛第二场The 2021 ICPC Asia Regionals Online Contest (II) L Euler Function

The 2021 ICPC Asia Regionals Online Contest (II)

The 2021 ICPC Asia Regionals Online Contest (II) M Addition

The Preliminary Contest for ICPC Asia Nanjing 2019/2019南京网络赛——题解