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\n",qq[i].res);
127         }
128     }
129
130     return 0;
131 }
时间: 2024-10-21 07:57:59

hdu 3938 portal的相关文章

hdu 3938 Portal(并查集+离线+kruskal)

搜了题解才把题搞明白.明白之后发现其实题意很清晰,解题思路也很清晰,只是题目表述的很不清晰…… 大意如下—— 给你一个无向图,图中任意两点的距离是两点间所有路径上的某一条边,这条边需要满足两个条件:1. 这条边这两点间某条路径上的最长边:2. 这条边是这两点间所有路径上的最长边中的最短边. 简单来说,假如a到d有两条路径,一条经过b,一条经过d,其中ab = 1, bd = 3, ac = 2, cd = 2,那么abd上的最长边为3,acd上的最长边为2,则ad的距离为2. 如果a, d两点间

HDU 3938:Portal(并查集+离线处理)

http://acm.hdu.edu.cn/showproblem.php?pid=3938 Portal Problem Description ZLGG found a magic theory that the bigger banana the bigger banana peel .This important theory can help him make a portal in our universal. Unfortunately, making a pair of port

HDU 3938 并查集

求小于L的路径点对数(路上的最大值),按权值排序,从小到大并查集建图,有点kruskal的意思. /** @Date : 2017-09-22 17:30:11 * @FileName: HDU 3938 并查集 离线.cpp * @Platform: Windows * @Author : Lweleth ([email protected]) * @Link : https://github.com/ * @Version : $Id$ */ #include <bits/stdc++.h>

数值标记问题 离线+树状数组 HDU 3938

题目大意:给你一个长度为n的数组a,定义区间[l,r]的val为区间内所有不同的数值之和.现在有m个询问,每次询问一个区间,问区间的val是多少. 思路:将所有的询问按照右端点排序.然后暴力枚举右区间,然后对之前出现过的val做一个标记即可,每次都更新这个标记就好了. 具体的和HDU 5869一样,只不过5869还要预处理,比较难 //看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace

hdu 3948 Portal (kusral+离线)

Portal Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 931    Accepted Submission(s): 466 Problem Description ZLGG found a magic theory that the bigger banana the bigger banana peel .This import

(离线处理+并查集) hdu 3938

Portal Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 977    Accepted Submission(s): 490 Problem Description ZLGG found a magic theory that the bigger banana the bigger banana peel .This import

集合问题 离线+并查集 HDU 3938

题目大意:给你n个点,m条边,q个询问,每条边有一个val,每次询问也询问一个val,定义:这样条件的两个点(u,v),使得u->v的的价值就是所有的通路中的的最长的边最短.问满足这样的点对有几个. 思路:我们先将询问和边全部都按照val排序,然后我们知道,并查集是可以用来划分集合的,所以我们就用并查集来维护每一个集合就行了. //看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespac

HDU 3938

并查集的离线算法. 题意是大坑.理解为寻找两点之间所有路径中的最长的边的值小于输入的值的点对的个数. 直接来代码. #include<stdio.h> #include<iostream> #include<algorithm> using namespace std; struct ab { int a,b,c; }; int n; struct ab poi[50050]; struct cd { int id,num,cc; }; struct cd li[500

图论 500题——主要为hdu/poj/zoj

转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并查集======================================[HDU]1213   How Many Tables   基础并查集★1272   小希的迷宫   基础并查集★1325&&poj1308  Is It A Tree?   基础并查集★1856   More i