zoukankan      html  css  js  c++  java
  • hdu5441(并查集+离线处理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5441

    题意:

      根据输入的三个整数n、m、q,表示有n座城市,m条路,q次询问。下面给出m行,每行三个数start、end、w,分别是这条道路的起点城市、终点城市、“权值”。然后给出q次询问的数值,每次询问的结果是符合条件的路有多少条。条件就是:如果这条路的权值比给的限制值要小,那么这条路就是可行的。注意就是:对于一条路的添加来说,只要a到b之间有路,那么符合条件的路就会有两条,一条是a到b,还有一条是b到a。比如:添加了两条路,a到b、b到c,那么其实答案就是6条,(a,b)、(a,c)、(b,a)、(b,c)、(c,a)、(c,b)。

    思路:

      刚开始用常规的并查集做法来写,发现会TLE,看了下数据,我之前那种遍历方法绝对会超时啊……看到q次询问就不加思索的对每次询问进行遍历,这样每次询问就要遍历一遍那m组数据,虽然实际可能不用遍历完m组,但是这个时间复杂度是很高的。然后网上学习了下,发现有一种方法很好,那就是不光对load[i].w进行排序,还可以对这q次询问的限制值进行排序这样的话只需要对m组数据遍历一次就够了。貌似这种方法有个名称叫做“离线处理”?(我个人理解应该是把查询的值先读入,读入后不在线处理,而是先存起来,排序之后再在遍历m组数据的时候使用)因为输出的时候是要按照输入时的顺序对应输出,所以这里需要有个表示查询值编号的数据。然后计算公式的话,两个集合合并,有增量有减量,合并后原来那两个集合不存在了,减量就是n1*(n1-1)、n2*(n2-1);合并后新出现的新集合存在一个增量:(n1+n2)*(n1+n2-1)。

    代码:

      1 #include<iostream>
      2 #include<algorithm>
      3 using namespace std;
      4 
      5 const int maxn = 2e4 + 10;
      6 const int max_edge = 1e5 + 10;
      7 const int max_q = 5e3 + 10;
      8 
      9 int fa[maxn];
     10 int num[maxn];    //记录这个集合中点的个数
     11 
     12 struct Load
     13 {
     14     int start;
     15     int end;
     16     int w;
     17 } load[max_edge];
     18 
     19 struct Qnode
     20 {
     21     int sum;
     22     int id;        //记录编号,便于最后输出时是按编号输出
     23 } qnode[max_q];
     24 
     25 bool cmp1(Load a, Load b)        //按权值从小到大排序
     26 {
     27     return a.w < b.w;
     28 }
     29 
     30 bool cmp2(Qnode a, Qnode b)        //按限制值从小到大排序
     31 {
     32     return a.sum < b.sum;
     33 }
     34 
     35 void init(int n)
     36 {
     37     for(int i = 1; i <= n; i++)
     38     {
     39         fa[i] = i;
     40         num[i] = 1;
     41     }
     42     return;
     43 }
     44 
     45 int find(int x)
     46 {
     47     if(fa[x] == x)
     48     {
     49         return x;
     50     }
     51     else
     52     {
     53         return fa[x] = find(fa[x]);
     54     }
     55 }
     56 
     57 int main()
     58 {
     59     ios::sync_with_stdio(false);
     60     int t;
     61     int n, m, q;
     62 
     63     long long ans[max_q];
     64 
     65     cin >> t;
     66 
     67     while(t--)
     68     {
     69         cin >> n >> m >> q;
     70         init(n);
     71         for(int i = 1; i <= m; i++)
     72         {
     73             cin >> load[i].start >> load[i].end >> load[i].w;
     74             //发现这个交换是多余的……
     75             /*if(load[i].start > load[i].end)
     76             {
     77                 swap(load[i].start, load[i].end);
     78             }*/
     79         }
     80         sort(load + 1, load + 1 + m, cmp1);
     81 
     82         for(int i = 1; i <= q; i++)
     83         {
     84             cin >> qnode[i].sum;
     85             qnode[i].id = i;    //编号按顺序赋值
     86         }
     87         sort(qnode + 1, qnode + 1 + q, cmp2);
     88 
     89         int cnt = 1;
     90         long long tmp = 0;
     91         for(int i = 1; i <= m; i++)    //这里是直接遍历路径数据,效率比我之前想的高多了……
     92         {
     93             int x = find(load[i].start);
     94             int y = find(load[i].end);
     95 
     96             while(load[i].w > qnode[cnt].sum && cnt <= q)
     97             {
     98                 ans[qnode[cnt].id] = tmp;    //没有新的路添加,所以答案还是tmp,暂时不变
     99                 cnt++;    //当前这个小的qnode不能满足大于这条路的权值,那么就继续往下看比当前大的qnode是否符合条件
    100             }
    101             if(x != y)
    102             {
    103                 long long n1 = num[x], n2 = num[y];
    104                 tmp += (n1 + n2) * (n1 + n2 - 1);
    105                 tmp -= (n1 * (n1 - 1) + n2 * (n2 - 1));
    106                 fa[x] = y;
    107                 num[y] += num[x];    //x合并到y上,则x上点的个数也要加到y上
    108             }
    109         }
    110         while(cnt <= q)    //这里的意思是,路径数据已经全部遍历完了,可能询问还没有结束,较小的询问已经处理过全部数据,那么较大的也一定能
    111         {
    112             ans[qnode[cnt++].id] = tmp;
    113         }
    114         for(int i = 1; i <= q; i++)
    115         {
    116             cout << ans[i] << endl;
    117         }
    118     }
    119     return 0;
    120 }
  • 相关阅读:
    为 WordPress 标签添加 rel="nofollow" 属性
    Discuz X3.2 SEO设置 title 不支持空格的解决方法
    LANMP 如何禁止访问 .htaccess 文件
    Discuz 哪些文件和文件夹需要777权限
    WordPress 模板常用函数
    CSS控制 table 的 cellpadding,cellspacing
    从 Typecho 自定义字段的调用代码看去
    Linux 服务器如何修改 DNS
    Linux 服务器如何禁止 ping 以及开启 ping
    Asp.Net 加载不同项目程序集
  • 原文地址:https://www.cnblogs.com/friend-A/p/9416942.html
Copyright © 2011-2022 走看看