P4383 [八省联考2018]林克卡特树

题目

分析

首先这个题需要转化。

发现对于删掉的每一条边,如果我们不走这个子树,那么其实删掉是毫无意义的,所以我们可以假设我们一定会走所有“割”下来的子树,那么其实我们可以更近一步,一定会走“割”下来的一条链?

然后因为这里可以剩下的部分不用割掉,所以我们可以考虑这样转化(这里只是略解,感性理解,实际可以去看看题解):求树上选择 \(k\) 条不交的链的权值之和的最大值。

发现这个可以dp,具体过程不再赘述。

然后我们闲来无事打了个表(\(k=1,2,3...\))发现这东西具有单调性(?)(似乎没有人给出证明)

于是可以考虑wqs二分,那么复杂度变成 \(O(n\log{V})\) ,可以通过。

代码

#include<bits/stdc++.h>
using namespace std;
//#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
const int N=3e5+5;
const ll INF=1e12;
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
int n,m;
ll l=-INF,r=INF,mid,ans=-1;
struct node{
	ll x,y;
	node(ll x=0,ll y=0):x(x),y(y){}
	inline bool operator < (const node &B)const{return x==B.x?y>B.y:x<B.x;}
	inline node operator + (const node &B)const{return node(x+B.x,y+B.y);}
	inline node operator + (const ll &B)const{return node(x+B,y);}
}dp[N][3];
int head[N],to[N<<1],nex[N<<1],val[N<<1],idx;
inline node ad(node x){return node(x.x-mid,x.y+1);}
inline void add(int u,int v,int w){nex[++idx]=head[u];to[idx]=v;val[idx]=w;head[u]=idx;return ;}
void dfs(int u,int fa){
    dp[u][2]=max(dp[u][2],node{-mid,1});
    for(int i=head[u];i;i=nex[i]){
        int v=to[i];
        if(v==fa) continue;
        dfs(v,u);
        dp[u][2]=max(dp[u][2]+dp[v][0],ad(dp[u][1]+dp[v][1]+val[i]));
        dp[u][1]=max(dp[u][1]+dp[v][0],dp[u][0]+dp[v][1]+val[i]);
        dp[u][0]=dp[u][0]+dp[v][0];
    }
    dp[u][0]=max(dp[u][0],max(ad(dp[u][1]),dp[u][2]));
}
signed main(){
	read(n),read(m);m++;
	ll T=0;
	for(int i=1;i<n;i++){
		int u,v,w;
		read(u),read(v),read(w);
		add(u,v,w),add(v,u,w);T+=abs(w);
	}
	l=-T,r=T;
	while(l<=r){
		mid=l+r>>1;
		memset(dp,0,sizeof(dp));
		dfs(1,0);
		if(dp[1][0].y<=m) r=mid-1;
		else l=mid+1;
	}
	memset(dp,0,sizeof(dp));
	mid=l;dfs(1,0);
	write(dp[1][0].x+m*l);
	return 0;
}
posted @ 2021-07-20 21:26  __Anchor  阅读(51)  评论(0编辑  收藏  举报