http://acm.hdu.edu.cn/showproblem.php?pid=5441
无向图,n个点,m条带权边,q次询问,给出数值d,点a可以到点b当且仅当存在一条路线其中最大的权值不超过d。
用sum记录连通块节点个数,两个连通块合并,结果增加( sum[a] + sum[b] ) * ( sum[a] + sum[b] - 1 ) - sum[a] * ( sum[a] - 1 ) - sum[b] * ( sum[b] -1 )
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int N=1e5+5; struct node { int a; int b; int c; }; int father[N]; node p[N]; int num[N]; ll sum[N];//表示该点所在连通块的节点个数 int r[N]; ll ans[N]; int finds(int x) { if(father[x]!=x) father[x]=finds(father[x]); return father[x]; } bool cmp(node x,node y) { return x.c<y.c; } void connect(int a,int b) { if(r[a]>r[b]) father[b]=a; else if(r[a]<r[b]) father[a]=b; else { father[a]=b; r[b]++; } sum[a]=sum[b]=sum[a]+sum[b]; } int main() { int T,cas=1; scanf("%d",&T); while(T--) { int n,m,q; scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++) { sum[i]=1; father[i]=i; scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c); } sort(p+1,p+m+1,cmp);//首先按权值进行排序 for(int i=1;i<=m;i++) { int a=finds(p[i].a); int b=finds(p[i].b); if(a!=b) { ans[i]=ans[i-1]+(sum[a]+sum[b])*(sum[a]+sum[b]-1)-sum[a]*(sum[a]-1)-sum[b]*(sum[b]-1);//连通块合并结果增加 connect(a,b); } else ans[i]=ans[i-1]; num[i]=p[i].c; } while(q--) { int x; scanf("%d",&x); int t=upper_bound(num+1,num+m+1,x)-num-1; printf("%lld ",ans[t]); } } return 0; }