HDU 4750 Count The Pairs kruskal
http://acm.hdu.edu.cn/showproblem.php?pid=4750
题意:
给出一些边,一个点到另一个点的一条路径,这条路径上的权值尽可能小,然后他给你一个t 值,
然你计算比 t 大的这些路径有多少条。
坑爹:
看了下边和点的数量,暴力是不行的,但也还是试了一下,因为当时实在想不到怎么做,就每次找
比 t 大的边然后向这条边上的两个点外拓展,最后只用计算一下两边点个数相乘再乘以二,最后发现是
不行的,因为我这次找到比 t 大所对应的边然后拓展出去所经过的边也有可能大于 t , 但是下次拓展到
这个边的时候就会有重复,一下子就不知道怎么弄了。
解法:
开始的时候也想过要做一些处理,因为那么大的数据暴力一定超时,但却忘记了kruskal加边的特性,
就是每次加最小的边,这样我们加边的时候每次以这条边上的两个点拓展的时候所经过的边一定小于原来
这个边。
1 #include<iostream> 2 #include<vector> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 500000 + 10; 7 8 struct Edge { 9 int v; 10 int u; 11 int w; 12 }edge[maxn]; 13 int n; 14 int m; 15 int father[maxn]; 16 int sum[maxn]; 17 int total[maxn]; 18 vector<int> V; 19 int cnt; 20 21 void init() 22 { 23 V.clear(); 24 int i; 25 for(i=0; i<maxn; i++) 26 { 27 father[i] = i; 28 sum[i] = 1; 29 total[i] = 0; 30 } 31 } 32 33 int cmp(Edge e1,Edge e2) 34 { 35 return e1.w < e2.w; 36 } 37 38 int find(int x) 39 { 40 if(x == father[x]) 41 { 42 return x; 43 } 44 return father[x] = find(father[x]); 45 } 46 47 void kruskal() 48 { 49 int i; 50 cnt = 1; 51 for(i=0; i<m; i++) 52 { 53 Edge e = edge[i]; 54 int root_A = find(e.u); 55 int root_B = find(e.v); 56 if(root_A != root_B) 57 { 58 V.push_back(e.w); 59 total[cnt++] = sum[root_A] * sum[root_B] * 2; 60 sum[root_B] += sum[root_A]; 61 father[root_A] = root_B; 62 } 63 } 64 for(i=1; i<cnt; i++) 65 { 66 total[i] += total[i-1]; 67 } 68 } 69 70 int main() 71 { 72 while(scanf("%d%d",&n,&m) != EOF) 73 { 74 init(); 75 int i; 76 for(i=0; i<m; i++) 77 { 78 int u; 79 int v; 80 int w; 81 scanf("%d%d%d",&u,&v,&w); 82 edge[i].u = u; 83 edge[i].v = v; 84 edge[i].w = w; 85 } 86 sort(edge,edge+m,cmp); 87 kruskal(); 88 89 int p; 90 scanf("%d",&p); 91 while(p--) 92 { 93 int t; 94 scanf("%d",&t); 95 int temp = lower_bound(V.begin(), V.end(), t) - V.begin(); 96 printf("%d\n",total[cnt-1] - total[temp]); 97 } 98 } 99 return 0; 100 }