注:窝是标题党,但是窝已经随机生成排了10w组了,但还是没找到QnQ,哭了/kk
第7个点比答案多 1
发现这题和点分治1差不多,多记每个点到根节点的边数,只用在双指针查找的时候顺带维护一下距离等于 k 的路径的边数就好了
只有双指针加了几行,其他的和点分治1没区别
求hack原理或者哪里写丑了
#include<bits/stdc++.h>
using namespace std;
template <class T>
inline T read(){
T r=0,f=0;char c=getchar();
while(!isdigit(c)) f|=c=='-',c=getchar();
while(isdigit(c)) r=(r<<3)+(r<<1)+(c^48),c=getchar();
return f?-r:r;
}
const int N=2e5+5,INF=1e9;
int n,k;
struct zfz{
int id,val,sum;
bool operator <(const zfz x)const{return val<x.val;}
}f[N];
int vis[N],type[N],cnt;
int flag,ans=INF;
int rootsum,sum,root,sz[N];
int hd[N],nx[N<<1],to[N<<1],val[N<<1],tote;
void adde(int u,int v,int c){
nx[++tote]=hd[u];to[tote]=v;val[tote]=c;hd[u]=tote;
nx[++tote]=hd[v];to[tote]=u;val[tote]=c;hd[v]=tote;
}
void findroot(int u,int father){
int maxx=0;sz[u]=1;
for(int i=hd[u];i;i=nx[i]){
int v=to[i];
if(v==father||vis[v]) continue;
findroot(v,u);
sz[u]+=sz[v],maxx=max(maxx,sz[v]);
}
maxx=max(maxx,sum-sz[u]);
if(rootsum>maxx) root=u,rootsum=maxx;
}
void dfs(int u,int father,int dis,int sub,int sum){
if(dis<=k) f[++cnt]=(zfz){u,dis,sum},type[u]=sub;
for(int i=hd[u];i;i=nx[i]){
int v=to[i];
if(v==father||vis[v]) continue;
dfs(v,u,dis+val[i],sub,sum+1);
}
}
void calc(int u){
cnt=0;
f[++cnt]=(zfz){u,0,0},type[u]=u;
for(int i=hd[u];i;i=nx[i]){
int v=to[i];
if(vis[v]) continue;
dfs(v,u,val[i],v,1);
}
sort(f+1,f+1+cnt);
int l=1,r=cnt;
while(l<r){
if(f[l].val+f[r].val>k) --r;
else{
if(f[l].val+f[r].val<k) ++l;
else{
if(type[f[l].id]==type[f[r].id]){
if(f[r].val==f[r-1].val) --r;
else ++l;
}
else{
flag=1,ans=min(ans,f[l].sum+f[r].sum);
if(f[r].val==f[r-1].val) --r;
else ++l;
}
}
}
}
}
void solve(int u){
vis[u]=1;calc(u);
for(int i=hd[u];i;i=nx[i]){
int v=to[i];
if(vis[v]) continue;
rootsum=n,sum=sz[v],findroot(v,u);
solve(root);
}
}
int main(){
n=read<int>(),k=read<int>();
for(int i=1;i<n;++i){
int x=read<int>()+1,y=read<int>()+1,z=read<int>();
adde(x,y,z);
}
rootsum=sum=n;
findroot(1,0);
solve(root);
if(!flag) puts("-1");
else printf("%d",ans);
return 0;
}