# 问题分析

1. 两次BFS可以找到树的直径, 基于规则是图没有变化, 显然这个题目中不太适用.
2. 一次DP可以找到树的直径, 并且DP方程是每次处理一个子树 ( 感觉可以为我所用? )

# DP讲解

D P [ u ] [ k + 1 ] = max ⁡ ( D P [ u ] [ p ] , D P [ v ] [ k − p ] + A ) , 如 果 D P [ u ] [ p ] + D P [ v ] [ l ] + A ≤ m i d D P [ u ] [ k ] = max ⁡ ( D P [ u ] [ p ] , D P [ v ] [ k − p ] + B ) , 如 果 D P [ u ] [ p ] + D P [ v ] [ l ] + B ≤ m i d DP[u][k+1] = \max({DP[u][p], DP[v][k-p] + A}), 如果 DP[u][p] + DP[v][l] + A \leq mid\\ DP[u][k] = \max({DP[u][p], DP[v][k-p] + B}), 如果 DP[u][p] + DP[v][l] + B \leq mid

# 代码

#include<bits/stdc++.h>
using namespace std;

const int N = 2e4+17, M = 4e4+17, K=21;
int fr[N], to[M], nxt[M], len1[M], len2[M], tails, size[N];
void add(int f, int t, int l1, int l2){
to[++tails] = t;
nxt[tails] = fr[f];
fr[f] = tails;
len1[tails] = l1;
len2[tails] = l2;
}

int n, m;
long long l, r, ans, mid, dp[N][K], tp[K];

void Check(int u, int fat){
size[u] = dp[u][0] = 0;
for(int p=fr[u], v;p;p=nxt[p]){
if((v=to[p])==fat)	continue;
Check(v, u);
int l1 = len1[p], l2 = len2[p];
int size1 = size[u], size2 = size[v];
int size3 = min(m, size1+size2+1);
for(int j=0;j<=size3;++j)	tp[j] = mid+1;
for(int j=0;j<=size1; ++j)
for(int k=0;k<=size2 && j+k<=m;++k){
if(dp[u][j] + dp[v][k] + l1 <= mid)
tp[j+k+1] = min(tp[j+k+1], max(dp[u][j], dp[v][k]+l1));
if(dp[u][j] + dp[v][k] + l2 <= mid)
tp[j+k] = min(tp[j+k], max(dp[u][j], dp[v][k]+l2));
}
size[u] = size3;
for(int j=0;j<=size3;++j)
dp[u][j] = tp[j];
}
return;
}

void work(){
scanf("%d %d",&n,&m);	tails = l = r = 0;
for(int i=1;i<=n;++i)	fr[i] = 0;
for(int i=1,p1,p2,l1,l2;i<n;++i){
scanf("%d%d%d%d",&p1, &p2, &l1, &l2);
r += max(l1, l2);
}
while(l <= r){
mid = (l+r)>>1;
Check(1, 0);
if(dp[1][m] <= mid){
ans = mid;
r = mid-1;
}else{
l = mid+1;
}
}
printf("%lld\n", ans);
}

int main(){
int T;scanf("%d",&T);
while(T--)	work();
return 0;
}

• 点赞
• 评论
• 分享
x

海报分享

扫一扫，分享海报

• 收藏
• 手机看

分享到微信朋友圈

x

扫一扫，手机阅读

• 打赏

打赏

SofanHe

你的鼓励将是我创作的最大动力

C币 余额
2C币 4C币 6C币 10C币 20C币 50C币
• 一键三连

点赞Mark关注该博主, 随时了解TA的最新博文
07-24 199

07-26 48
07-17 1413
04-22