P4657 [CEOI2017]Chase

不得不说这个树形dp做法真牛

题目大意:给出一棵树,求一条路径,选择路上的V个点,使得被选择的点的相邻且不在路径上的点的权值和最大。

考虑换根的话很麻烦 还是类似毛毛虫那个题 每个点一定是处于一个路径的中间的 可能是一上一下 一下一上 一下 一上这四种情况

因为这个题目是有方向性的 a->b 的权值和 是不等于b->a 的 所以次大最大的方案也不是很好做 这个题解法的灵魂就是去重的操作

设b[x][i] 表示从x向x的子树走取i个点的最大权值和

设c[x][i] 表示从x的子树走到x取i个点的最大权值和

设g[x]表示x周围的点的权值和

设f[x]表示x点的权值

转移方程:

b[u][i]=max(b[u][i],b[v][tot-i]+g[u]-f[fa])
c[u][i]=max(c[u][i],c[v][tot-i]+g[u]-f[v])

答案:ans=max(ans,c[u][i]+b[v][tot-i],c[u][tot],b[u][tot])

设当前节点为x,y1,y2,y3...为x的儿子

为了避免重复走相同的路径 我们在不断在y跟新x之前就先统计答案

比如我们先跟新了y1和y2 此时在加入y3之前就跟新ans

我们用的是y1和y2跟新的c[][] 和y3的b[][]跟新的答案 所以c里面一定不包含y3

这个题的解决办法真的好优美

#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
int N,V,x,y,tot,top,F[maxn],sta[maxn];
int son[maxn<<1],nxt[maxn<<1],lnk[maxn];
long long g[maxn],c[maxn][105],b[maxn][105],ans;
inline int read() {
	int ret=0,f=1,ch=getchar();
	for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
	for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
	return ret*f;
}
inline void add_edge(int x,int y) {
	son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;
	son[++tot]=x,nxt[tot]=lnk[y],lnk[y]=tot;
}
inline void DP(int x,int y,int f) {
//  ans一定要在前面赋值,这样可以避免从y走到x又走回y
	for (int i=1; i<=V; ++i) ans=max(ans,c[x][i]+b[y][V-i]);
	for (int i=1; i<=V; ++i)
		c[x][i]=max(c[x][i],max(c[y][i],c[y][i-1]+g[x]-F[y])),
		b[x][i]=max(b[x][i],max(b[y][i],b[y][i-1]+g[x]-F[f]));
}
void dfs(int x,int pre) {
	for (int i=1; i<=V; ++i) c[x][i]=g[x],b[x][i]=g[x]-F[pre];
	for (int k=lnk[x]; k; k=nxt[k]) if (son[k]^pre) dfs(son[k],x),DP(x,son[k],pre);
//  对于节点x,y和z是它的子节点并且,y先于z遍历。
//  上面的方法,无法计算z->x->y所以要倒着做一遍
	for (int i=1; i<=V; ++i) c[x][i]=g[x],b[x][i]=g[x]-F[pre];
	top=0;for (int k=lnk[x]; k; k=nxt[k]) if (son[k]^pre) sta[++top]=son[k];
	for (int i=top; i; --i) DP(x,sta[i],pre);
	ans=max(ans,max(c[x][V],b[x][V]));
}
int main() {
	N=read(),V=read();
	for (int i=1; i<=N; ++i) F[i]=read();
	for (int i=1; i<N; ++i) add_edge(x=read(),y=read()),g[x]+=F[y],g[y]+=F[x];
	return dfs(1,0),printf("%lld",ans),0;
}
posted @ 2022-04-22 10:15  wzx_believer  阅读(32)  评论(0编辑  收藏  举报