这题是一道有点难的点分治,但是我的想法和标算好像有些出入诶……
考虑点分治的一般套路,都是先求树的重心,然后计算当前子树中所有非树根节点到树根节点的距离,最后根据题目要求统计答案。
这题嘛,还是一样的套路,对于当前子树,记录 所有已经搜索过的非树根节点 到树根的距离 所需的最小深度。(这句话要好好理解)
然后在统计答案时,就用当前节点的深度加上k减去当前节点到树根的距离所需的最小深度来更新答案即可。
但是对于同一子树间的判重,我还不是弄得很清楚,需要反复思考。
等我弄懂之时,再来更新吧。
附上AC代码:
#include <cstdio>
#include <cctype>
#define N 200010
#define INF 2e9
using namespace std;
struct side{
int to,w,nt;
}s[N<<1];
struct note{
int dep,dis;
}d[N];
int n,m,x,y,w,num,h[N],mx[N],ans,sum,t[1000010],rt,size[N],dis[N],dep[N],top,pre;
bool b[N];
inline char nc(){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=a*10+c-'0',c=nc());
a*=f;return;
}
inline void add(int x,int y,int w){
s[++num]=(side){y,w,h[x]},h[x]=num;
s[++num]=(side){x,w,h[y]},h[y]=num;
}
inline int max(int a,int b){
return a>b?a:b;
}
inline int min(int a,int b){
return a<b?a:b;
}
inline void so(int x,int fa){
size[x]=1,mx[x]=0;
for (int i=h[x]; i; i=s[i].nt)
if (!b[s[i].to]&&s[i].to!=fa)
so(s[i].to,x),size[x]+=size[s[i].to],mx[x]=max(mx[x],size[s[i].to]);
mx[x]=max(mx[x],sum-size[x]);
if (mx[x]<mx[rt]) rt=x;
return;
}
inline void get(int x,int fa){
if (dis[x]>m) return;
d[++top].dep=dep[x],d[top].dis=dis[x];
ans=min(ans,dep[x]+t[m-dis[x]]);
for (int i=h[x]; i; i=s[i].nt)
if (!b[s[i].to]&&s[i].to!=fa){
dis[s[i].to]=dis[x]+s[i].w,dep[s[i].to]=dep[x]+1;
if (dis[s[i].to]<=m) get(s[i].to,x);
}
return;
}
inline void calc(int x){
dis[x]=dep[x]=top=0,pre=1;
for (int i=h[x]; i; i=s[i].nt)
if (!b[s[i].to]){
dep[s[i].to]=1,dis[s[i].to]=s[i].w,get(s[i].to,x);
for (int j=pre; j<=top; ++j)
if (d[j].dis<=m) t[d[j].dis]=min(t[d[j].dis],d[j].dep);
pre=top+1;
}
for (int i=1; i<=top; ++i)
if (d[i].dis<=m) t[d[i].dis]=INF;
t[0]=0;return;
}
inline void work(int x){
calc(x),b[x]=1;
for (int i=h[x]; i; i=s[i].nt)
if (!b[s[i].to])
sum=size[s[i].to],rt=0,so(s[i].to,0),work(rt);
return;
}
int main(void){
read(n),read(m);
for (int i=1; i<n; ++i) read(x),++x,read(y),++y,read(w),add(x,y,w);
mx[0]=ans=INF,sum=n;
for (int i=1; i<=m; ++i) t[i]=INF;
so(1,0),work(rt);
printf("%d",ans==INF?-1:ans);
return 0;
}