题:https://www.luogu.com.cn/problem/P4149
题意:找出树上点对距离恰好为k的点对,且点对之间的距离最小,要是不存在输出-1;
分析:对于每次的dfs的每次u,对于u的每一个孩子v,先计数路径,再把v的子树含的路径更新到桶里。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #include<tr1/unordered_map> using namespace std; typedef long long ll; #define pb push_back const int M=2e5+5; const int inf=0x3f3f3f3f; struct node{ int v; ll w; }; vector<node>g[M]; unordered_map<ll,ll>mp; ll ans,n; ll k; ll sz[M],deep[M],son[M],vis[M]; ll dis[M]; void dfs1(int u,int fa){ sz[u]=1; deep[u]=deep[fa]+1; for(auto i:g[u]){ int v=i.v; ll w=i.w; if(v!=fa){ dis[v]=dis[u]+w; dfs1(v,u); sz[v]+=sz[u]; if(sz[son[u]]<sz[v]) son[u]=v; } } } void cal(int u,int fa,int root){ ll tmp=k-dis[u]+2*dis[root]; if(mp[tmp]){ ans=min(ans,mp[tmp]+deep[u]-2*deep[root]); } for(auto i:g[u]){ int v=i.v; if(v!=fa&&!vis[v]) cal(v,u,root); } } void update(int u,int fa,int p){ if(p==1){ if(mp[dis[u]]==0) mp[dis[u]]=deep[u]; else mp[dis[u]]=min(mp[dis[u]],deep[u]); } else mp[dis[u]]=0; for(auto i:g[u]){ int v=i.v; if(v!=fa&&!vis[v]) update(v,u,p); } } void dfs2(int u,int fa,int sign){ for(auto i:g[u]){ int v=i.v; if(v!=fa&&v!=son[u]) dfs2(v,u,0); } if(son[u]) dfs2(son[u],u,1),vis[son[u]]=1; for(auto i:g[u]){ int v=i.v; if(v!=fa&&!vis[v]){ cal(v,u,u); update(v,u,1); } } if(mp[dis[u]]==0) mp[dis[u]]=deep[u]; else mp[dis[u]]=min(mp[dis[u]],deep[u]); if(mp[dis[u]+k]) ans=min(ans,mp[dis[u]+k]-deep[u]); if(son[u]) vis[son[u]]=0; if(!sign) update(u,fa,0),mp[dis[u]]=0; } int main(){ scanf("%lld%lld",&n,&k); for(int i=1;i<n;i++){ int u,v; ll w; scanf("%d%d%lld",&u,&v,&w); u++,v++; g[u].pb(node{v,w}); g[v].pb(node{u,w}); } dfs1(1,0); ans=inf; dfs2(1,0,0); if(ans==inf) puts("-1"); else printf("%d ",ans); return 0; } /** 4 3 0 1 1 1 2 2 1 3 4 */