题目的描述有点玄学。
但发现把一个树切成k+1个联通块后,再连接起来并且找一个最长的路径的方法,显然是这个k+1个联通块首尾相接,直径连直径。
进一步的,这个问题等价于在树上选择恰好k+1条链,不允许点相交,路径可以为一个点,使得路径长度之和最大。
这个东西首先可以用一个O(nk)的dp来搞,然而n<=1e5。
对于这类严格数量限制问题,可以用wqs二分来解决,二分一下偏移量,dp的时候保存一下当前的链的数量,数量越多越好。
如果权值最优方案中,选择的链的数量<k+1,则令l=mid+1,反之同理。
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<vector>
#include<cstdlib>
#include<algorithm>
#define N 1100000
#define eps 1e-7
#define ll long long
using namespace std;
inline ll read()
{
char ch=0;
ll x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*flag;
}
const ll inf=1e9+7;
struct edge
{
ll to,nxt,w;
}e[N*2];
ll num=-1,head[N];
inline void add(ll x,ll y,ll z)
{
e[++num]=(edge){y,head[x],z};head[x]=num;
e[++num]=(edge){x,head[y],z};head[y]=num;
}
struct node{ll x,t;}dp[N][3];
bool operator<(node a,node b){if(a.x!=b.x)return a.x<b.x;else return a.t<b.t;}
node operator+(node a,node b){return (node){a.x+b.x,a.t+b.t};}
void dfs(ll x,ll fa,ll k)
{
dp[x][0]=(node){0,0};dp[x][1]=(node){-inf,-inf};dp[x][2]=(node){k,1};
for(ll i=head[x];i!=-1;i=e[i].nxt)
{
ll to=e[i].to;
if(to==fa)continue;
dfs(to,x,k);
node o=max(dp[to][0],max(dp[to][1],dp[to][2]));
dp[x][2]=
max
(
dp[x][2]+o,
max
(
dp[x][1]+dp[to][1]+(node){e[i].w-k,-1},
dp[x][1]+dp[to][0]+(node){e[i].w,0}
)
);
dp[x][1]=
max
(
dp[x][1]+o,
max
(
dp[x][0]+dp[to][1]+(node){e[i].w,0},
dp[x][0]+dp[to][0]+(node){e[i].w+k,1}
)
);
dp[x][0]=dp[x][0]+o;
}
}
int main()
{
memset(head,-1,sizeof(head));
ll n=read(),k=read()+1;
for(ll i=1;i<=n-1;i++)
{
ll x=read(),y=read(),z=read();
add(x,y,z);
}
ll l=-inf,r=+inf,mid;
while(l<r)
{
mid=((l+r)>>1);
dfs(1,1,mid);
node o=max(dp[1][0],max(dp[1][1],dp[1][2]));
if(o.t<k)l=mid+1;
else r=mid;
}
dfs(1,1,l);
printf("%lld",max(dp[1][0],max(dp[1][1],dp[1][2])).x-k*l);
return 0;
}