大意:告诉你有n个点 m个边的无向图
然后问有多少点对 他们的路径上节点之间的距离都少于 x
思路:
并查集
离线处理。将边权值按从小到大排序,查询标号后按照从小到大排序。对于每次查询,依次将比当前查询值小的边加入并查集。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int t; int n,m,q; struct path { int starts; int ends; int weight; bool operator <(const path &x)const{ return weight<x.weight; } }P[100000 + 5]; struct input { int id; int limit; bool operator <(const input &x)const{ return limit < x.limit; } }L[100000 + 5]; long long ans[5000 + 5]; int father[20000 + 5]; int cnt[20000 + 5]; int Find(int x) { return father[x] == x ? x : father[x] = Find(father[x]); } void init() { for (int j = 1; j <= n; j++) { father[j] = j; cnt[j] = 1; } memset(ans,0,sizeof(ans)); } int main() { scanf("%d", &t); while (t--) { scanf("%d%d%d", &n, &m, &q); for (int i = 0; i < m; i++) scanf("%d %d %d", &P[i].starts, &P[i].ends, &P[i].weight); sort(P, P + m); for (int i = 0; i < q; i++) { L[i].id = i; scanf("%d", &L[i].limit); } sort(L, L + q); init(); int cur = 0; long long sum = 0; for (int i = 0; i < q; i++) { while (cur < m && L[i].limit >= P[cur].weight) { int fstarts = Find(P[cur].starts); int fends = Find(P[cur].ends); if(fstarts != fends) { sum += cnt[fstarts] * cnt[fends]; //将总联通块合并,再将合并之前的已有的减去,得到的算式化简得 father[fends] = fstarts; cnt[fstarts] += cnt[fends]; } cur++; } ans[L[i].id] = sum; } for(int i = 0; i < q; i++) printf("%lld ", 2 * ans[i]); } return 0; }