Description
给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.
Input
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
Sample Input
4 3
0 1 1
1 2 2
1 3 4
0 1 1
1 2 2
1 3 4
Sample Output
2
好激动啊我过了IOI的题【虽然是水题】
考虑点分治。对于每棵树记录子节点到根的距离,用vx[x]来存储前面子树的子节点到根的路径中长度为x的最少经历的边数。
然后每次扫一遍更新下ANS就可以了
#include<cstdio>
#include<algorithm>
using namespace std;
struct line
{
int s,t;
int x;
int next;
}a[400001];
int head[200001];
int edge;
inline void add(int s,int t,int x)
{
a[edge].next=head[s];
head[s]=edge;
a[edge].s=s;
a[edge].t=t;
a[edge].x=x;
}
int mini,minx;
int son[200001];
bool v[200001];
inline void find(int d,int fa,int s)
{
son[d]=0;
int i;
int tmp=0;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(t!=fa&&!v[t])
{
find(t,d,s);
son[d]+=(son[t]+1);
tmp=max(tmp,son[t]+1);
}
}
int mx=max(tmp,s-tmp-1);
if(mx<minx||mx==minx&&d<mini)
{
minx=mx;
mini=d;
}
}
struct save
{
int x,d;
bool operator <(save y)const
{
return x<y.x;
}
}sx[200001];
int dis[200001],dep[200001];
int vx[2000001];
int p,k;
inline void dfs(int d,int fa)
{
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(t!=fa&&!v[t])
{
dis[t]=dis[d]+a[i].x;
dep[t]=dep[d]+1;
p++;
sx[p].x=dis[t];
sx[p].d=dep[t];
dfs(t,d);
}
}
}
int ans=2100000000;
inline void solve(int d)
{
v[d]=true;
int i,j;
int l,r;
p=0;
int p1=0;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t])
{
dis[t]=a[i].x;
dep[t]=1;
p++;
sx[p].x=dis[t];
sx[p].d=dep[t];
p1=p;
dfs(t,d);
for(j=p1;j<=p;j++)
if(sx[j].x<k)
if(vx[k-sx[j].x]!=2100000000)
ans=min(vx[k-sx[j].x]+sx[j].d,ans);
for(j=p1;j<=p;j++)
{
if(sx[j].x==k)
ans=min(ans,sx[j].d);
if(sx[j].x<=k)
vx[sx[j].x]=min(vx[sx[j].x],sx[j].d);
}
}
}
for(i=1;i<=p;i++)
if(sx[i].x<=k)
vx[sx[i].x]=2100000000;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t])
{
mini=0;
minx=2100000000;
find(t,d,son[t]);
int root=mini;
solve(root);
}
}
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
int n;
scanf("%d%d",&n,&k);
int i;
int s,t,x;
for(i=1;i<=n-1;i++)
{
scanf("%d%d%d",&s,&t,&x);
s++;
t++;
edge++;
add(s,t,x);
edge++;
add(t,s,x);
}
mini=0;
minx=2100000000;
find(1,0,n);
int root=mini;
for(i=1;i<=2000000;i++)
vx[i]=2100000000;
solve(root);
if(ans==2100000000)
printf("-1\n");
else
printf("%d\n",ans);
return 0;
}