http://acm.hdu.edu.cn/showproblem.php?pid=5441
题意:
给出一个图,每条边有一个距离,现在有多个询问,每个询问有一个距离值d,对于每一个询问,计算出有多少点对(x,y)使得在x到y的路径上没有一条边的距离大于d。
思路:
只要边距离小于d,那就是可行的,直接加入并查集来维护。并查集需要维护一下树的节点个数。
将边和询问都排序离线处理。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 8 int n,m,k; 9 int p[20005], num[20005]; 10 ll ans[5005]; 11 12 13 struct node 14 { 15 int u,v,w; 16 bool operator< (const node& rhs) const 17 { 18 return w<rhs.w; 19 } 20 }e[100005]; 21 22 struct Node 23 { 24 int id; 25 int val; 26 bool operator< (const Node& rhs) const 27 { 28 return val<rhs.val; 29 } 30 }query[5005]; 31 32 33 int finds(int x) 34 { 35 return x==p[x]?x:p[x] = finds(p[x]); 36 } 37 38 int main() 39 { 40 //freopen("in.txt","r",stdin); 41 int T; 42 scanf("%d",&T); 43 while(T--) 44 { 45 scanf("%d%d%d",&n,&m,&k); 46 for(int i=1;i<=n;i++) {p[i] = i; num[i] = 1;} 47 for(int i=1;i<=m;i++) 48 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 49 sort(e+1,e+m+1); 50 for(int i=1;i<=k;i++) 51 { 52 scanf("%d",&query[i].val); 53 query[i].id = i; 54 } 55 sort(query+1,query+k+1); 56 query[0].id = 0; 57 ll tmp = 0; 58 int pos = 1; 59 ans[0] = 0; 60 for(int i=1;i<=m && pos<=k;i++) 61 { 62 while(e[i].w>query[pos].val && pos<=k) 63 { 64 ans[query[pos].id] = ans[query[pos-1].id]; 65 pos++; 66 } 67 while(e[i].w<=query[pos].val && i<=m) 68 { 69 int x = finds(e[i].u); 70 int y = finds(e[i].v); 71 if(x!=y) 72 { 73 p[x] = y; 74 tmp = tmp-num[y]*(num[y]-1)-num[x]*(num[x]-1); 75 num[y] += num[x]; 76 tmp = tmp+num[y]*(num[y]-1); 77 } 78 i++; 79 } 80 ans[query[pos].id] = tmp; 81 pos++; 82 i--; 83 } 84 while(pos<=k) 85 { 86 ans[query[pos].id] = ans[query[pos-1].id]; 87 pos++; 88 } 89 for(int i=1;i<=k;i++) printf("%lld\n",ans[i]); 90 } 91 return 0; 92 }