如果在第$i$个询问时,图上没有边权小于$k_i$的边,那么答案就是$v_i$所在连通块的大小减一。
那么可以先将询问按$k_i$降序排序,将边按边权降序排序。
这样每次询问之前,把边权不小于$k_i$的边用并查集并上即可。
代码(100分):
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<map> #include<set> #define IL inline #define RG register #define _1 first #define _2 second using namespace std; const int N=1e5; int n,m; struct Edge{ int u,v,w; }e[N+3]; int p; IL bool operator<(Edge a,Edge b){ return a.w>b.w; } struct Qry{ int k,v,d; }q[N+3]; IL bool operator<(Qry a,Qry b){ return a.k>b.k; } int f[N+3],sz[N+3],c[N+3]; int find(int x){ return f[x]==x?x:f[x]=find(f[x]); } IL void merge(int x,int y){ if(sz[x]<sz[y]) swap(x,y); f[y]=x; sz[x]+=(sz[x]==sz[y]); c[x]+=c[y]; } int ans[N+3]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<n;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); for(int i=1;i<=m;i++){ scanf("%d%d",&q[i].k,&q[i].v); q[i].d=i; } sort(e+1,e+n); sort(q+1,q+m+1); p=1; for(int i=1;i<=n;i++){ f[i]=i; sz[i]=c[i]=1; } for(int i=1;i<=m;i++){ for(;e[p].w>=q[i].k;p++) merge(find(e[p].u),find(e[p].v)); ans[q[i].d]=c[find(q[i].v)]-1; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
原文:https://www.cnblogs.com/Hansue/p/12917850.html