给一棵树,每条边有权。求一条简单路径,权值和等于 K ,且边的数量最小。
淀粉质的题,直接套淀粉质的板子,再维护一个桶,表示到达dis的最小需要的路径。
但是有个奇怪的东西,就是如果我最后还原的时候用栈储存所有的dis就会WA4个点,但是如果我把dfs重做一遍就没事了。。。WA了1页。。。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,k,head[200005],ecnt,rt,f[200005],siz[200005],size;
struct Edge{int to,nxt,val;}e[400005];
bool vis[200005];
void add(int bg,int ed,int val) {e[++ecnt]=(Edge){ed,head[bg],val};head[bg]=ecnt;}
void barycenter(int x,int fa) {
f[x]=0,siz[x]=1;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(v==fa||vis[v]) continue;
barycenter(v,x),f[x]=max(f[x],siz[v]),siz[x]+=siz[v];
}
f[x]=max(f[x],size-siz[x]);
if(f[x]<f[rt]) rt=x;
}
int dis[1000005],stk[1000005],top,ans;
bool used[1000005];
void dfs(int x,int fa,int val,int along) {
dis[val]=min(dis[val],along);
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(vis[v]||v==fa) continue;
if(val+e[i].val<=k)
dfs(v,x,val+e[i].val,along+1);
}
}
void calc(int x,int fa,int val,int dep) {
if(val==k) ans=min(ans,dep),dis[k]=min(dis[k],dep);
ans=min(ans,dis[k-val]+dep);
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(vis[v]||v==fa) continue;
if(val+e[i].val<=k) calc(v,x,val+e[i].val,dep+1);
}
}
void dfs2(int x,int fa,int val) {
dis[val]=0x3f3f3f3f;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(vis[v]||v==fa)continue;
if(val+e[i].val<=k) dfs2(v,x,e[i].val+val);
}
}
void work(int x) {
top=0;dis[0]=0;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(vis[v]) continue;
if(e[i].val<=k)
calc(v,x,e[i].val,1),dfs(v,x,e[i].val,1);
}
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v]) continue;
dfs2(v,x,e[i].val);
}
}
void solve(int x) {
vis[x]=1;
work(x);
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;rt=0;
if(vis[v]) continue;
siz[rt]=size=siz[v];
barycenter(v,0);
solve(rt);
}
}
int main() {
scanf("%d%d",&n,&k);
memset(dis,0x3f,sizeof dis);dis[0]=0;ans=n;
for(int i=1,a,b,c;i<n;i++) {scanf("%d%d%d",&a,&b,&c);add(a+1,b+1,c);add(b+1,a+1,c);}
size=n,f[0]=n;rt=0;
barycenter(1,0);
solve(rt);
if(ans!=n)cout<<ans;
else cout<<-1;
}