分析:
显然有个
O
(
N
∗
K
)
O(N*K)
O(N∗K)的方法。
裸的树上背包。根节点分类讨论那种。
然后这要T
于是:
即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立。略去过程Q.E.D.,由上可知证毕。
这个背包随着背包容量L是单峰的。
然后就可以用WQS二分,每次给一条链强行+某个值,使得最优解恰有K条链。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 300010
typedef long long ll;
using namespace std;
vector<int> a[MAXN];
vector<ll> w[MAXN];
struct node{
ll x,y;
node () {}
node (ll x1,ll y1):x(x1),y(y1) {}
bool operator < (const node &a) const {
if(x!=a.x)
return x<a.x;
return y>a.y;
}
node operator + (const node &a) const {
return node(x+a.x,y+a.y);
}
node operator + (ll a) const {
return node(x+a,y);
}
}f[MAXN][3];
ll add;
void dfs(int x,int fa){
f[x][2]=max(f[x][2],node(-add,1));
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==fa)
continue;
dfs(u,x);
f[x][2]=max(f[x][2]+f[u][0],f[x][1]+f[u][1]+node(-add,1ll)+w[x][i]);
f[x][1]=max(f[x][1]+f[u][0],f[x][0]+f[u][1]+w[x][i]);
f[x][0]=f[x][0]+f[u][0];
}
f[x][0]=max(f[x][0],max(f[x][2],f[x][1]+node(-add,1)));
}
node check(){
memset(f,0,sizeof f);
dfs(1,0);
return max(f[1][0],max(f[1][2],f[1][1]+node(-add,1)));
}
int n;
ll k;
int main(){
// freopen("data.in","r",stdin);
SF("%d%lld",&n,&k);
k++;
ll r=0,l;
int u,v;ll val;
for(int i=1;i<n;i++){
SF("%d%d%lld",&u,&v,&val);
a[u].push_back(v);
a[v].push_back(u);
w[u].push_back(val);
w[v].push_back(val);
r+=abs(val);
}
l=-r;
while(l<=r){
int mid=(l+r)>>1;
add=mid;
// PF("[%lld %lld: %lld -> %lld]\n",l,r,add,check().y);
if(check().y<=k)
r=mid-1;
else
l=mid+1;
}
add=l;
PF("%lld",check().x+add*k);
}