题目:给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000
思路:先找到根,然后求出经过根的路径数最小的方案。在处理一个节点时,用已处理的信息加上当前点的信息来更新答案,t[i]表示距离根为i的节点的最小深度,dis[i]表示i节点离根的距离,ans=min(ans,t[k-dis[i]]+d[i])。处理完根的一个子树后再更新一下信息,可以保证答案经过根。对每个子树分治一下就好了。
#include <cstdio>
#include <vector>
using namespace std;
inline char tc(void)
{
static char fl[1000000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,1000000,stdin),A==B)?EOF:*A++;
}
inline int read(void)
{
int a=0;static char c;
while((c=tc())<'0'||c>'9');
while(c>='0'&&c<='9')
a=a*10+c-'0',c=tc();
return a;
}
struct Edge
{
int to,cost;
Edge(int t,int c):to(t),cost(c){}
};
int n,k,t[1000001],mx[200001],size[200001],d[200001],dis[200001],sum,root,ans=1e9;
char vis[200001];
vector<Edge>edge[200001];
void dfs1(int x,int fa)
{
register int i;
size[x]=1,mx[x]=0;
for (i=0;i<edge[x].size();++i)
if(!vis[edge[x][i].to]&&edge[x][i].to!=fa)
dfs1(edge[x][i].to,x),mx[x]=max(mx[x],size[edge[x][i].to]),size[x]+=size[edge[x][i].to];
mx[x]=max(mx[x],sum-size[x]);mx[x]<mx[root]?root=x:0;
return ;
}
void add(int x,int fa,int flag)
{
register int i;
flag?t[dis[x]]=min(t[dis[x]],d[x]):t[dis[x]]=1e9;
for (i=0;i<edge[x].size();++i)
if(!vis[edge[x][i].to]&&edge[x][i].to!=fa&&dis[edge[x][i].to]<=k)
add(edge[x][i].to,x,flag);
return ;
}
void cal(int x,int fa)
{
register int i;
ans=min(ans,t[k-dis[x]]+d[x]);
for (i=0;i<edge[x].size();++i)
if(!vis[edge[x][i].to]&&edge[x][i].to!=fa)
{
d[edge[x][i].to]=d[x]+1;
dis[edge[x][i].to]=dis[x]+edge[x][i].cost;
if(dis[edge[x][i].to]<=k)
cal(edge[x][i].to,x);
}
return ;
}
void work(int x)
{
register int i;
vis[x]=1,t[0]=0;
for (i=0;i<edge[x].size();++i)
if(!vis[edge[x][i].to])
dis[edge[x][i].to]=edge[x][i].cost,d[edge[x][i].to]=1,
dis[edge[x][i].to]<=k?cal(edge[x][i].to,0),add(edge[x][i].to,0,1),0:0;
for (i=0;i<edge[x].size();++i)
if(!vis[edge[x][i].to])
dis[edge[x][i].to]<=k?add(edge[x][i].to,0,0),0:0;
for (int i=0;i<edge[x].size();++i)
if(!vis[edge[x][i].to])
sum=size[edge[x][i].to],root=0,dfs1(edge[x][i].to,0),work(root);
return ;
}
int main(void)
{
register int i,x,y,z;
n=read(),k=read();
for (i=1;i<=k;++i)
t[i]=1e9;
for (i=1;i<n;++i)
x=read()+1,y=read()+1,z=read(),edge[x].push_back(Edge(y,z)),edge[y].push_back(Edge(x,z));
sum=n,mx[0]=1e9,dfs1(1,0),work(root);
return ans==1e9?puts("-1"):printf("%d",ans),0;
}