解析
它还真的不难。
乐。
这题没做出来有些谔谔。
外层wqs二分显而易见,里面不知道为啥我总觉得这个题可以贪心。
然后一直试图在原树直径上下功夫,一筹莫展。
看到题解“dp”两个字这题也就做完了…
就相当于要把一棵树分成若干条无交链,每分条需要一定代价,最大化价值和。
记录以下每个点向儿子连几条边以及是否和父亲连边之类的即可。
(pair
用于wqs二分的dp是真香)
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;
const int N=6e5+100;
const ll inf=3e11;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,k;
struct node{
int to,nxt,w;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y,int w){
p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;
}
#define pr pair<ll,ll>
#define mkp make_pair
pr operator + (pr a,pr b){return mkp(a.first+b.first,a.second+b.second);}
pr operator + (pr a,ll b){return mkp(a.first+b,a.second);}
pr dp[3][N];
ll w;
void dfs(int x,int fa){
dp[0][x]=mkp(0,0);
dp[1][x]=dp[2][x]=mkp(-inf,0);
for(int i=fi[x];~i;i=p[i].nxt){
int to=p[i].to;
if(to==fa) continue;
dfs(to,x);
dp[2][x]=max(dp[2][x],max(dp[2][x]+dp[0][to],(dp[1][x]+dp[1][to])+p[i].w));
dp[1][x]=max(dp[1][x],max(dp[1][x]+dp[0][to],(dp[0][x]+dp[1][to])+p[i].w));
dp[0][x]=max(dp[0][x],dp[0][x]+dp[0][to]);
}
dp[1][x]=max(dp[1][x],dp[0][x]);
dp[0][x]=max(dp[0][x],mkp(dp[0][x].first+w,dp[0][x].second+1));
dp[0][x]=max(dp[0][x],mkp(dp[1][x].first+w,dp[1][x].second+1));
dp[0][x]=max(dp[0][x],mkp(dp[2][x].first+w,dp[2][x].second+1));
return;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
memset(fi,-1,sizeof(fi));cnt=-1;
n=read();m=read()+1;
for(int i=1;i<n;i++){
int x=read(),y=read(),w=read();
addline(x,y,w);addline(y,x,w);
}
ll st=-inf,ed=inf;
while(st<ed){
ll mid=(st+ed)>>1;
w=mid;
dfs(1,0);
if(dp[0][1].second>=m) ed=mid;
else st=mid+1;
}
w=st;
debug("w=%lld\n",w);
dfs(1,0);
printf("%lld\n",dp[0][1].first-m*w);
return 0;
}