hdu 3938 portal

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
",qq[i].res);
127         }
128     }
129 
130     return 0;
131 }
犹豫就会败北!
原文地址:https://www.cnblogs.com/kickit/p/7147036.html