這個題,大佬說是水題,對我這種菜雞來說,看了好久才懂。。。。
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
/*
①如果k==c,那麼起點和終點至少有一個是陷阱(可能有些人會認爲終點一定會是陷阱,這樣是沒錯的,因爲起點和終點時相對的,你也可以把起點看做終點)。
②如果k<c,那麼起點和終點是否是陷阱是任意的,可以有也可以沒有。
*/
//這個題和CCF上做的第四題差不多,dp[i][j]做樹形dp是模板,這裏加了陷阱的條件,自然要多一維。
const int N = 50010;
vector<int> g[N];
int val[N],trap[N];
long long dp[N][4][2];
int T,n,c;
long long ans;
void dfs(int parent,int child){
dp[child][trap[child]][trap[child]] = val[child];
ans = max(ans,dp[child][trap[child]][trap[child]]);//是原來的路好,還是以child做起點更好???????????
for(int i=0;i<g[child].size();i++){
int v = g[child][i];
if(v==parent) continue;
dfs(child,v);
/*=================================================================================================*/
//有點像區間dp了,是把兩個鏈拼起來的
//這裏應該和下面分開來看,這裏是單獨更新ans的過程,這裏並不需要考慮v是child子節點這個特殊關係
//只有子節點纔可以拼接啊。
//在上面的dfs中,已經更新了v及其子節點的dp值。
for(int j=0;j<=c;j++){
for(int k=0;j+k<=c;k++){
//child和v起點都是陷阱
//
if(j+k<=c) ans = max(ans,dp[child][j][1]+dp[v][k][1]);
//j+k==c時,不能執行這一句,因爲child和v起點都不是陷阱,不可能。
if(j+k<c) ans = max(ans,dp[child][j][0]+dp[v][k][0]);
//j==c時不執行這一句,因爲若執行,j==c,起點又不是陷阱,不可能,child還要往下拼接,不能是陷阱。
if(j!=c) ans = max(ans,dp[child][j][0]+dp[v][k][1]);
if(k!=c) ans = max(ans,dp[child][j][1]+dp[v][k][0]);
}
}
/*==============================================================================================*/
//j+trap[child] 很可能就==c了!!!所以沒得打問題,下面的if只是不能用這裏更新罷遼,
//把這裏更新的覆蓋掉。
for(int j=0;j<c;j++){
dp[child][j+trap[child]][0] = max(dp[child][j+trap[child]][0],dp[v][j][0]+val[child]);
dp[child][j+trap[child]][1] = max(dp[child][j+trap[child]][1],dp[v][j][1]+val[child]);
}
//如果child不是陷阱,那麼起點肯定就是陷阱了。
//那此時我們走線就是相反的,應該是從child走到起點。
//那如果child是陷阱,那麼起點可以是也可以不是,這裏爲何不更新呢??
//在上面for那裏更新了。
if(!trap[child]) dp[child][c][1] = max(dp[child][c][1],dp[v][c][1]+val[child]);
}
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&c);
/*===========================新一輪,全清零=========================*/
ans=0;
for(int i=0;i<n;i++){
g[i].clear();
}
memset(dp,-inf,sizeof(dp));//不能是0,得是-inf,爲啥?
//詳情可見:https://blog.csdn.net/tri_integral/article/details/9499037 下方評論
//因爲如果是0,這一句“dp[child][j+trap[child]][1] = max(dp[child][j+trap[child]][1],dp[v][j][1]+val[child]);”
//0++val[child] 很可能會超過前面,但其實這個0不對。
//仔細想想,此時正確的值不是0,而是這個數據無意義。(從理解的角度來說)
/*========================================================================================================*/
for(int i=0;i<n;i++){
scanf("%d %d",&val[i],&trap[i]);
}
int a=0,b=0;
for(int i=0;i<n-1;i++){
scanf("%d %d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
dfs(-1,0);
printf("%lld\n",ans);
}
return 0;
}