众所周知,点分治模板一是询问是否有树上路径长度为K 而这道题问路径长度为K的最小边数
所以在我用其中一种正解(桶+点分治 O(nlogn) ) 过了这题后
我寻思着这两题这么像(看起来),可不可以在判断合法的那里改成找最优的水过去
因为模板那道题只是问是否存在,而这道题是要求最优,所以不能匹配到一组后就退出了,而应找出其它的合法的
对于一种不合法的情况,即revl,revr属于一种子树是肯定要排除掉的,模板那道题是判断revr和revr−1是否相同来调整的。我想着对于这道题,应该是要尽量找到更多的组,所以就弄了个失配数组fail,在匹配失败的时候让r跳,复杂度很玄学,但是在洛谷能过。。。
但这种写法显然是错误的,在ybtOj上被更强的数据hack了。。。如果可以的话,建议加强下数据。。。
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
#define N 200010
using namespace std;int n,l[N],k,tot,u,v,m;
struct node{int next,to;LL w;}e[N<<1];
LL w,K;
inline void add(int u,int v,LL w){e[++tot]=(node){l[u],v,w};l[u]=tot;return;}
inline LL read()
{
char c;LL d=1,f=0;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
bool vis[N];
int siz[N],f[N],sum,rt,len[N];
inline void Getrt(int x,int fa=0)
{
siz[x]=1;f[x]=0;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa||vis[y]) continue;
Getrt(y,x);siz[x]+=siz[y];f[x]=max(f[x],siz[y]);
}
f[x]=max(f[x],sum-siz[x]);if(f[x]<f[rt]) rt=x;return;
}
LL dis[N],rev[N];int cnt,a[N],belong[N];
inline void Getdis(int x,int fa=0,int which=0)
{
rev[++cnt]=x;belong[x]=which;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa||vis[y]) continue;
dis[y]=dis[x]+e[i].w;len[y]=len[x]+1;
Getdis(y,x,which);
}return;
}
int ans=0x3f3f3f3f,fail[N];
inline bool cmp(int x,int y){return dis[x]<dis[y];}
inline void Doit(int x)
{
cnt=1;rev[cnt]=x;dis[x]=0;belong[x]=x;len[x]=0;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(vis[y]) continue;
dis[y]=e[i].w;len[y]=1;
Getdis(y,x,y);
}
sort(rev+1,rev+1+cnt,cmp);
int l=1,r=cnt;fail[cnt]=cnt+1;
for(register int i=cnt-1;i;i--) fail[i]=(belong[rev[i]]==belong[rev[i+1]])?fail[i+1]:i+1;
for(;l<r;++l)
{
for(;l<r&&dis[rev[r-1]]+dis[rev[l]]>=K;r--);
if(belong[rev[l]]==belong[rev[r]]) r=fail[r];
while(r<=cnt&&dis[rev[l]]+dis[rev[r]]==K)
{
if(belong[rev[l]]!=belong[rev[r]]) ans=min(ans,len[rev[l]]+len[rev[r]]);
r=fail[r];
}
}
return;
}
inline void Solve(int x)
{
vis[x]=1;Doit(x);
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(vis[y]) continue;
f[rt=0]=n;sum=siz[y];
Getrt(y,x);Solve(rt);
}
return;
}
signed main()
{
n=read();K=read();
for(register int i=1;i<n;i++) u=read()+1,v=read()+1,w=read(),add(u,v,w),add(v,u,w);
f[0]=sum=n;Getrt(1);Solve(rt);
if(ans==0x3f3f3f3f) puts("-1");else
printf("%d",ans);
}