解析
它还真的不难。
乐。
这题没做出来有些谔谔。
外层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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifmemset(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;
}