Description
给一棵有N(1 <= N <= 200000)个结点的树,每条边有权,求一条路径,权值和等于K(1 <= K <= 1000000)且边的数量最小。
Input
第一行两个整数 n, k
第2到n行每行三个整数,表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
输出仅一个整数,表示最小边数量,如果不存在这样的路径,则输出-1
Sample Input
4 3 0 1 1 1 2 2 1 3 4
Sample Output
2
刚做的时候发现水题一道啊,甚至不需要去重复:
inline void Calc(int x){
DocDist(x,cnt=0,0,0);
sort(a+1,a+1+cnt);
int L=1,r=cnt;
while(L<r){
if(a[L].dis+a[r].dis==k)ans=min(ans,a[L].num+a[r].num),--r;
if(a[L].dis+a[r].dis>k)--r;
if(a[L].dis+a[r].dis<k)++L;
}
}
然后调了很久愣是不知道哪里错了,结果画了个图就gg了:
如果黑边+红边=k。。。还是太菜了,这个都想不到= =但上述写法居然可以水很多分
然而冥思苦想甚久,我毅然决然地做好了co标准备= =
其实想法是一样的= =不需要去重,我们只需统计子树之间的贡献就可以了,详情见代码:
#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
const int N = 2e5+10;
struct Edge{
int to[N<<1],next[N<<1],w[N<<1];
int cnt,h[N];
inline void add(int x,int y,int z){
next[++cnt]=h[x];
to[cnt]=y;
w[cnt]=z;
h[x]=cnt;
}
}e;
struct edge{
int dis,num;
bool operator <(const edge&A)const{
return dis<A.dis;
}
}a[N];
int n,k;
struct PF{
int Minsiz,siz[N];
int G,sum,ans;
bool vst[N];
int cnt,num[N*5];
inline void FindG(int x,int fa){//找重心
int Maxsiz=0;
siz[x]=1;
for(int p=e.h[x];p;p=e.next[p])if(e.to[p]^fa&&!vst[e.to[p]]){
FindG(e.to[p],x);
siz[x]+=siz[e.to[p]];
Maxsiz=max(Maxsiz,siz[e.to[p]]);
}
Maxsiz=max(Maxsiz,sum-siz[x]);
if(Maxsiz<Minsiz)G=x,Minsiz=Maxsiz;
}
inline void DocDist(int x,int fa,int dist,int num){
a[++cnt]=(edge){dist,num};
for(int p=e.h[x];p;p=e.next[p])if(e.to[p]^fa&&!vst[e.to[p]]){
DocDist(e.to[p],x,dist+e.w[p],num+1);
}
}
inline void Calc(int x){
num[0]=cnt=0;
for(int p=e.h[x];p;p=e.next[p])if(!vst[e.to[p]]){
int tmp=cnt;
DocDist(e.to[p],x,e.w[p],1);//我们以重心为根,统计距离
Inc(i,tmp+1,cnt)if(a[i].dis<=k)ans=min(ans,num[k-a[i].dis]+a[i].num);//注意这两个循环的顺序,显然如果先做下一个循环,就变成了之前(错误)
Inc(i,tmp+1,cnt)if(a[i].dis<=k)num[a[i].dis]=min(num[a[i].dis],a[i].num);//的思想,因为子树内部的贡献是会出问题的
}
Inc(i,1,cnt)if(a[i].dis<=k)num[a[i].dis]=0x3f3f3f3f;
}
inline void stat(int x){
Minsiz=1<<30;
FindG(x,0);
vst[G]=1;
Calc(G);
for(int p=e.h[G];p;p=e.next[p])if(!vst[e.to[p]]){
sum=siz[e.to[p]];//注意改sum
stat(e.to[p]);
}
}
}p;
inline void init(){
scanf("%d%d",&n,&k);
Inc(i,1,n-1){
int x,y,w;scanf("%d%d%d",&x,&y,&w);
e.add(x+1,y+1,w),e.add(y+1,x+1,w);
}
p.ans=p.sum=n;
memset(p.num,63,sizeof(p.num));
}
int main(){
init();
p.stat(1);
if(p.ans==n)puts("-1");
else cout<<p.ans<<'\n';
return 0;
}