题解 P4657 [CEOI2017]Chase
Solution
当我们固定一个起点后 , 把起点作为整个树的根 , 那么这时每个节点选不选的价值就是它所有儿子的铁球数量加和 .
那么设
设
枚举起点作为根 , 复杂度
不能通过本题 ,
考虑沿用上面对价值的定义 , 设计新的 dp,
设
设当前节点为
那么有转移
注意路径方向的不同导致的价值变化 .
还要考虑
即
但直接使用一个点的
那么考虑在合并子树时更新答案 ,
注意这里
上式的
时间复杂度
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define ll long long
using namespace std;
int read()
{
int ret=0;char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return ret;
}
const int maxn=1e5+5;
const int maxm=105;
const ll inf=1e15;
int n,v;
ll ans;
struct graph
{
int p[maxn];ll val[maxn];
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
void add(int x,int y){ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void link(int x,int y){add(x,y);add(y,x);}
ll f[maxn][maxm][2],g[maxn][maxm][2];
void dfs(int u,int fa)
{
val[u]=0;
for(int i=head[u];i;i=nxt[i])
{
if(ver[i]==fa)continue;
dfs(ver[i],u);val[u]+=p[ver[i]];
}
f[u][0][1]=g[u][0][1]=-inf;
g[u][1][1]=max(g[u][1][1],val[u]+p[fa]);
for(int i=head[u];i;i=nxt[i])
{
if(ver[i]==fa)continue;
ll mx1=0,mx2=0;
for(int j=v;j>=0;j--)
{
mx1=max(mx1,max(g[u][v-j][0],g[u][v-j][1]));
mx2=max(mx2,max(f[u][v-j][0],f[u][v-j][1]+p[fa]-p[ver[i]]));
ans=max(ans,max(f[ver[i]][j][0],f[ver[i]][j][1])+mx1);
ans=max(ans,max(g[ver[i]][j][0],g[ver[i]][j][1])+mx2);
}
for(int j=1;j<=v;j++)
f[u][j][0]=max(f[u][j][0],max(f[ver[i]][j][0],f[ver[i]][j][1])),f[u][j][1]=max(f[u][j][1],max(f[ver[i]][j-1][0],f[ver[i]][j-1][1])+val[u]);
for(int j=1;j<=v;j++)
g[u][j][0]=max(g[u][j][0],max(g[ver[i]][j][0],g[ver[i]][j][1])),g[u][j][1]=max(g[u][j][1],max(g[ver[i]][j-1][0],g[ver[i]][j-1][1])+val[u]+p[fa]-p[ver[i]]);
}
}
}o;
int main()
{
n=read();v=read();
for(int i=1;i<=n;i++)o.p[i]=read();
for(int i=1;i<=n-1;i++)o.link(read(),read());
o.dfs(1,0);
printf("%lld",ans);
return 0;
}