我们在 kruskal 重构树上找到 $x$ 到根的路径上权值 $\leq val$ 的最浅的节点。显然这就是所有满足条件的节点所在的子树的根节点。
+??? note "[「LOJ 137」最小瓶颈路 加强版](https://loj.ac/problem/137)"
+
+ ```
+ #include<bits/stdc++.h>
+
+ using namespace std;
+
+ const int MAX_VAL_RANGE = 280010;
+
+ int n,m,log2Values[MAX_VAL_RANGE + 1];
+
+ namespace TR
+ {
+ struct Edge
+ {
+ int to,nxt,val;
+ }e[400010];
+ int cnt,head[140010];
+
+ void addedge(int u,int v,int val=0)
+ {
+ e[++cnt]=(Edge){v,head[u],val};
+ head[u]=cnt;
+ }
+
+ int val[140010];
+ namespace LCA
+ {
+ int sec[280010],cnt;
+ int pos[140010];
+ int dpth[140010];
+
+ void dfs(int now,int fa)
+ {
+ dpth[now]=dpth[fa]+1;
+ sec[++cnt]=now;
+ pos[now]=cnt;
+
+ for(int i=head[now];i;i=e[i].nxt)
+ {
+ if(fa!=e[i].to)
+ {
+ dfs(e[i].to,now);
+ sec[++cnt]=now;
+ }
+ }
+ }
+
+ int dp[280010][20];
+ void init()
+ {
+ dfs(2*n-1,0);
+ for(int i=1;i<=4*n;i++)
+ {
+ dp[i][0]=sec[i];
+ }
+ for(int j=1;j<=19;j++)
+ {
+ for(int i=1;i+(1<<j)-1<=4*n;i++)
+ {
+ dp[i][j]=dpth[dp[i][j-1]]<dpth[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
+ }
+ }
+ }
+
+ int lca(int x,int y)
+ {
+ int l=pos[x],r=pos[y];
+ if(l>r)
+ {
+ swap(l,r);
+ }
+ int k=log2Values[r - l + 1];
+ return dpth[dp[l][k]]<dpth[dp[r-(1<<k)+1][k]]?dp[l][k]:dp[r-(1<<k)+1][k];
+ }
+ }
+ }
+
+ using TR::addedge;
+
+ namespace GR
+ {
+ struct Edge
+ {
+ int u,v,val;
+
+ bool operator<(const Edge &other)const
+ {
+ return val<other.val;
+ }
+ }e[100010];
+
+ int fa[140010];
+
+ int find(int x)
+ {
+ return fa[x]==0?x:fa[x]=find(fa[x]);
+ }
+
+ void kruskal()
+ {
+ int tot=0,cnt=n;
+ sort(e+1,e+m+1);
+ for(int i=1;i<=m;i++)
+ {
+ int fau=find(e[i].u),fav=find(e[i].v);
+ if(fau!=fav)
+ {
+ cnt++;
+ fa[fau]=fa[fav]=cnt;
+ addedge(fau,cnt);
+ addedge(cnt,fau);
+ addedge(fav,cnt);
+ addedge(cnt,fav);
+ TR::val[cnt]=e[i].val;
+ tot++;
+ }
+ if(tot==n-1)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ int ans;
+ int A,B,C,P;
+ inline int rnd()
+ {
+ return A=(A*B+C)%P;
+ }
+
+ void initLog2()
+ {
+ for(int i = 2;i <= MAX_VAL_RANGE;i++) {
+ log2Values[i] = log2Values[i >> 1] + 1;
+ }
+ }
+
+ int main()
+ {
+ initLog2();
+ cin>>n>>m;
+ for(int i=1;i<=m;i++)
+ {
+ int u,v,val;
+ cin>>u>>v>>val;
+ GR::e[i]=(GR::Edge){u,v,val};
+ }
+ GR::kruskal();
+ TR::LCA::init();
+ int Q;
+ cin>>Q;
+ cin>>A>>B>>C>>P;
+
+ while(Q--)
+ {
+ int u=rnd()%n+1,v=rnd()%n+1;
+ ans+=TR::val[TR::LCA::lca(u,v)];
+ ans%=1000000007;
+ }
+ cout<<ans;
+ return 0;
+ }
+ ```
+
??? note "[NOI 2018 归程](https://www.luogu.org/problem/P4768)"
首先预处理出来每一个点到根节点的最短路。
询问的根节点可以使用 kruskal 重构树上倍增的方式求出。
时间复杂度 $O((n+m+Q) \log n)$
+
+
+??? note "[「LOJ 137」最小瓶颈路 加强版](https://loj.ac/problem/137)"