https://vjudge.net/problem/HDU-3938
题意:
给出一张带权图,给出q个查询,问对于每个查询可以修建多少个传送门。两个点之间可以修建传送门的条件是两点之间的最长边小于等于每次问询的l。就是从n个点中选择2个点的问题。
思路:
这题的数据有点大,最开始想出来了正确的做法,但是t了,一开始的思路是统计一共有多少个连通分量,然后用组合计数,但是复杂度达到了O(n * n),后来看了题解。
题解的思路是离线的,先把每一个查询都输入,然后我们把每一个来连通分量看成一个点,将所有的q排序,将所有的边按照权值排序,然后q为外层循环,边为内层循环,每一次一旦出现边的权值大于q的情况,就记录下此时的边的位置,下次就从这条边开始。因为q是非递减的,所以每一次的ans都可以以前面的作为基础,进行累加。对于每一条边,当它的两个节点已经在同一连通分量中时,ans不变,因为还是在相同数量的点中选择2点,当不连通时,就把两个连通分量的大小相乘,加到ans中,这里是组合的思想,然后将两点连通,并且大小互相加。最后输出就行了。
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 7 struct node 8 { 9 int a,b,c; 10 } e[50005]; 11 12 struct qu 13 { 14 int id,nu; 15 long long res; 16 } qq[10005]; 17 18 int par[10005]; 19 20 int v[10005]; 21 22 void init(int n) 23 { 24 for (int i = 1;i <= n;i++) 25 par[i] = i; 26 for (int i = 1;i <= n;i++) 27 v[i] = 1; 28 } 29 30 int fin(int x) 31 { 32 if (x == par[x]) return x; 33 else return par[x] = fin(par[x]); 34 } 35 36 void unit(int x,int y) 37 { 38 x = fin(x); 39 y = fin(y); 40 41 if (x != y) par[x] = y; 42 } 43 44 bool cmp1(node aa,node bb) 45 { 46 return aa.c < bb.c; 47 } 48 49 bool cmp2(qu aa,qu bb) 50 { 51 return aa.nu < bb.nu; 52 } 53 54 bool cmp3(qu aa,qu bb) 55 { 56 return aa.id < bb.id; 57 } 58 59 int main() 60 { 61 int n,m,q; 62 63 while (scanf("%d%d%d",&n,&m,&q) != EOF) 64 { 65 memset(v,0,sizeof(v)); 66 67 init(n); 68 69 for (int i = 0;i < m;i++) 70 { 71 scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c); 72 } 73 74 for (int i = 0;i < q;i++) 75 { 76 scanf("%d",&qq[i].nu); 77 qq[i].id = i; 78 } 79 80 sort(e,e+m,cmp1); 81 82 sort(qq,qq+q,cmp2); 83 84 long long ans = 0; 85 86 int mark = 0; 87 88 for (int j = 0;j < q;j++) 89 { 90 int l = qq[j].nu; 91 92 for (int i = mark;i < m;i++) 93 { 94 if (e[i].c <= l) 95 { 96 int x = e[i].a,y = e[i].b; 97 98 if (fin(x) != fin(y)) 99 { 100 int rt1 = fin(x),rt2 = fin(y); 101 102 ans += v[rt1] * v[rt2]; 103 104 long long t1 = v[rt1],t2 = v[rt2]; 105 106 unit(x,y); 107 108 v[rt2] += t1; 109 v[rt1] += t2; 110 } 111 } 112 else 113 { 114 mark = i; 115 break; 116 } 117 } 118 119 qq[j].res = ans; 120 } 121 122 sort(qq,qq+q,cmp3); 123 124 for (int i = 0;i < q;i++) 125 { 126 printf("%I64d\n",qq[i].res); 127 } 128 } 129 130 return 0; 131 }
时间: 2024-10-21 07:57:59