Acwing 264. 权值

给定一棵 N 个节点的树,每条边带有一个权值。

求一条简单路径,路径上各条边的权值和等于K,且路径包含的边的数量最少。
输入格式

第一行两个整数 N, K。

第2~N行每行三个整数x,y,z,表示一条无向边的两个端点x,y和权值z,点的编号从0开始。
输出格式

输出一个整数,表示最少边数量。

如果不存在满足要求的路径,输出-1。
数据范围

N≤200000,K≤1000000

输入样例:

4 3
0 1 1
1 2 2
1 3 4

输出样例:

2

题解:点分治
用数组记录经过当前根的路径长度一样时最少边数tmp
同时记得不能用memset会TLE。用递归O(N)初始化。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=200005*5,K=1000005*5;
int tot,n,k,head[N],nex[N],ans=1e9,ver[N],val[N],d[N];
int v[N],tmp[K],size[N];
int pos,mine=1e9;
inline void add(int x,int y,int z){
    nex[++tot]=head[x];head[x]=tot;ver[tot]=y;val[tot]=z;
}
inline int get_gravity(int x,int larg){
	v[x]=1;size[x]=1;
	int mm=0;
	for(int i=head[x];i;i=nex[i]){
		if(v[ver[i]])continue;
		get_gravity(ver[i],larg);
		mm=max(mm,size[ver[i]]);
	    size[x]+=size[ver[i]];
	}
	mm=max(mm,larg-size[x]);
	if(mm<mine){
		pos=x;mine=mm;
	}
    v[x]=0;
}

inline void tree_dfs_ask(int p,int cnt){
	v[p]=1;
	if(d[p]==k)ans=min(ans,cnt);
	else if(d[p]<k){if(tmp[k-d[p]]!=0)
		ans=min(ans,tmp[k-d[p]]+cnt);
	}
	for(int i=head[p];i;i=nex[i]){
		int y=ver[i];
		if(v[y])continue;
		d[y]=d[p]+val[i];
		tree_dfs_ask(y,cnt+1);
    }
    v[p]=0;
}
inline void tree_dfs_change(int p,int cnt){
	v[p]=1;
	if(d[p]<=k)tmp[d[p]]= tmp[d[p]]==0?cnt:min(cnt,tmp[d[p]]);
	for(int i=head[p];i;i=nex[i]){
		int y=ver[i];
		if(v[y])continue;
		d[y]=d[p]+val[i];
		tree_dfs_change(y,cnt+1);
	}
	v[p]=0;
}
inline void clearing(int x){
	if(d[x]<=k)tmp[d[x]]=0;
	for(int i=head[x];i;i=nex[i]){
		int y=ver[i];
		if(v[y])continue;
		v[y]=1;
		d[y]=d[x]+val[i];
		clearing(y);
		v[y]=0;
	}
}
inline void dfs(int p,int larg){
	v[p]=1;
	if(size[p]==1)return ;
	for(int i=head[p];i;i=nex[i]){
		int y=ver[i];
		if(v[y])continue;
		d[y]=val[i];
		tree_dfs_ask(y,1);
		tree_dfs_change(y,1);
	}
	d[p]=0;
	clearing(p);
	for(int i=head[p];i;i=nex[i]){
		int y=ver[i];
		if(v[y])continue;
		mine=1e9;
		get_gravity(y,size[y]);
		mine=1e9;
		get_gravity(pos,size[y]);
		dfs(pos,size[pos]);
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>k;
	for (int i=1; i<n; i++){
		int x,y,z;
		cin>>x>>y>>z;x+=1;y+=1;
		add(x,y,z);add(y,x,z);
	}
	get_gravity(1,n);
	get_gravity(pos,n);
	dfs(pos,size[pos]);
	if(ans==1e9)cout<<-1<<endl;
	else cout<<ans<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值