Description
0v0在野外看到了一棵Galo树,看到食物的0v0瞪大了眼睛,变成了OvO。
这棵Galo树可以看做是一棵以1号点为根的n个点的有根数,除了根节点以外,每个节点i都有一个Galo,美味度为w[i]。
OvO发现,如果她摘下了i号Galo,那么i的子树中的Galo以及i到根的路径上的其他Galo都会死掉。
OvO的袋子只能装k个Galo,她的嘴巴里还能叼1个,请问她所摘Galo的美味度之和的最大值是多少?
Input
第一行两个正整数n,k。
第二行到第n行,第i行两个正整数f[i],w[i],表示i号点的父亲为f[i] (保证x[i]
Output
一行一个非负整数,为最大美味值。
Sample Input
4 1
1 10
2 3
2 6
Sample Output
10
Data Constraint
30% n,k<=200
另30% n*k*k<=10^7
另40% n*k<=10^7
对于所有数据,n,k,w[i]<=10^5
Hint
尽管OvO最多可以摘两个Galo,但是最优情况是只摘下第二个点的Galo,美味度为10。
题解
这是一棵树,自然联想树上的算法。
设
fi,j
表示在以i为根节点的子树中,选了j个的最大美味度。
转移有两种情况:
1、第i个点选,那么它子树里面就不能选。
fi,1=wi
2、在子树里面选择,树形背包合并。
但这样的时间复杂度是 O(nk2)
树形dp还有另外一种变型,就是按照dfs序来dp。
记录每一个点的子树大小
si
那么
fi,j
同样有两种转移
1、由
fi+1,j
,选i的子树。
2、由
fi+sdfni,j
,就是选了i
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 100003
#define db double
#define P putchar
#define G getchar
#define mo 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
void writeln(ll x){write(x);P('\n');}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int n,k,f[N*103],dfn[N],si[N],w[N],ans;
int tot,to[N],b[N],nxt[N],x;
void ins(int x,int y)
{
nxt[++tot]=b[x];
to[tot]=y;
b[x]=tot;
}
void dfs(int x)
{
dfn[++dfn[0]]=x;
for(int i=b[x];i;i=nxt[i])
dfs(to[i]),si[x]+=si[to[i]];
si[x]++;
}
int V(int i,int j)
{
return (i-1)*(k+1)+j;
}
int main()
{
freopen("galo.in","r",stdin);
freopen("galo.out","w",stdout);
read(n);read(k);k++;
for(int i=2;i<=n;i++)
read(x),read(w[i]),ins(x,i);
dfs(1);
/*
for(int i=n;i;i--)
for(int j=1;j<=k;j++)
f[i][j]=max(f[i+1][j],f[i+si[dfn[i]]][j-1]+w[dfn[i]]);*/
for(int i=n;i;i--)
for(int j=1;j<=k;j++)
f[V(i,j)]=max(f[V(i+1,j)],f[V(i+si[dfn[i]],j-1)]+w[dfn[i]]);
for(int i=1;i<=k;i++)
ans=max(ans,f[V(1,i)]);
writeln(ans);
}