HDU 5441 Travel (并查集+数学+计数)

题意:给你一个带权的无向图,然后q(q≤5000)次询问,问有多少对城市(城市对(u,v)与(v,u)算不同的城市对,而且u≠v)之间的边的长度不超过d(如果城市u到城市v途经城市w,

那么需要城市u到城市w的长度e1≤d,同时城市w到城市v的长度e2≤d)。

析:一开始的时候,题意都读错了,怎么看都不对,原来是只要最大的d小于等于x就可以,过了好几天才知道是这样。。。。。

这个题是并查集的应用,先从d小的开始遍历,然后去判断有几个连通块,在连通块中计数,用一个数组即可,运用排列组合的知识可以知道一个连通块中, 一共有

n * (n-1)对,然后不断更新连通块中结点的数量即可,先排序再输出。其实并不难。要注意加结点的时候,谁是谁是父结点,这个是很重要的。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
using namespace std ;

typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-8;
const int maxn = 2e4 + 5;
const int mod = 1e9 + 7;
const int dr[] = {0, 0, -1, 1};
const int dc[] = {-1, 1, 0, 0};
int n, m;
inline bool is_in(int r, int c){
    return r >= 0 && r < n && c >= 0 && c < m;
}
struct node{
    int u, v, w;
    bool operator < (const node &p) const{
        return w < p.w;
    }
};
node a[maxn*5];
struct node1{
    int id, w;
    bool operator < (const node1 &p) const{
        return w < p.w;
    }
};
node1 x[5005];
int p[maxn], w[maxn], ans[maxn];

int Find(int x){  return x == p[x] ? x : p[x] = Find(p[x]); }

int main(){
    int T;  cin >> T;
    while(T--){
        int q;
        scanf("%d %d %d", &n, &m, &q);
        for(int i = 1; i <= n; ++i)  p[i] = i, w[i] = 1;
        for(int i = 0; i < m; ++i)  scanf("%d %d %d", &a[i].u, &a[i].v, &a[i].w);
        for(int i = 0; i < q; ++i)  scanf("%d", &x[i].w), x[i].id = i;
        sort(a, a+m);
        sort(x, x+q);

        int j = 0, num = 0;
        for(int i = 0; i < q; ++i){
            while(j < m && a[j].w <= x[i].w){
                int xx = Find(a[j].u);
                int yy = Find(a[j].v);
                if(xx != yy){
                    num -= w[xx] * (w[xx]-1) + w[yy] * (w[yy]-1);
                    w[xx] += w[yy];
                    w[yy] = 0;
                    num += w[xx] * (w[xx]-1);
                    p[yy] = xx;//注意父结点的选取
                }
                ++j;
            }
            ans[x[i].id] = num;
        }

        for(int i = 0; i < q; ++i)
            printf("%d\n", ans[i]);
    }
    return 0;
}
时间: 2024-12-06 00:42:58

HDU 5441 Travel (并查集+数学+计数)的相关文章

HDU 5441 Travel 并查集

HDU 5441 Travel 题意:一张无向图,q个查询,对于每个x,有多少对点之间的路径中最长的一条路不大于x. 思路:比赛时王秋平写的,我补下题.这题也比较简单,将边排序,从小到大加到并查集,对查询也排序,从小到大对于每个查询把不大于x的边加到并查集,用cnt[y]记录以y为根的连通块有多少节点,那么在连通块发生 变化时,ans=2 * cnt[x] * cnt[y] 1 #include <iostream> 2 #include <cstdio> 3 #include &

2015 ACM/ICPC Asia Regional Changchun Online HDU - 5441 (离线+并查集)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5441 题意:给你n,m,k,代表n个城市,m条边,k次查询,每次查询输入一个x,然后让你一个城市对(u,v)满足两点之间每一条边都不超过x,问有多少对 思路:首先我想到的是dfs求出每个查询小于等于他的一个连通块,然后num*(num-1)就是答案,但是时间只有一秒,这个复杂度是5*1e8,超时了(亲身体验了) 然后我们想这个是离线的,我们可不可以由小到大来推,这样前面的贡献到后面就依然能用了,但是我们

Hdu 2473(并查集删除操作) Junk-Mail Filter

有木有很吊 加强 加强版   啊  ,看了都不敢做了   ,后来先做了食物链这个我还是看过的,但还是A不掉,没明白神魔意思 ,总而言之,大牛的博客是个好东西,我就那么看了一下,还是不懂怎莫办啊,哎,就那样就A掉了....... 今天我们来谈一下这个并查集的删除操作,根据我对大牛的理解啊,这个并查集的删除操作并不是把原来的节点删除掉,而是用一个替身替掉,现在的这个点只是用作桥梁的作用,即是无用的,del  ,,,del  ,,,,删除,那些被删掉的就从n开始给他们一个地址,然后即如下代码所示 #i

HDU 4496 D-City(并查集,逆思维)

题目 熟能生巧...常做这类题,就不会忘记他的思路了... //可以反过来用并查集,还是逐个加边,但是反过来输出...我是白痴.....又没想到 //G++能过,C++却wa,这个也好奇怪呀... #include<stdio.h> #include<string.h> int fx,fy,r,bin[10010]; int x[100010],y[100010],n,m,i,count,ans[100010],j; int find(int x) { //改成这样就不会超时了么好

HDU 1272 简单并查集

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24915    Accepted Submission(s): 7641 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双

hdu 3038 (并查集)

题目大意: 给出m个询问,问[l,r]之间的和   ,求出有多少次询问不和之前的矛盾的. 思路分析: 用并查集记录当前节点到根节点的和. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define maxn 222222 using namespace std; int set[maxn]; int sum[maxn]; int find(int

hdu 5441 Travel 离线带权并查集

Travel Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5441 Description Jack likes to travel around the world, but he doesn’t like to wait. Now, he is traveling in the Undirected Kingdom. There are n cities and m

Hdu 5441 Travel(并查集)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5441 思路:离线处理.将边权值按从小到大排序,查询标号后按照从小到大排序.对于每次查询,依次将比当前查询值小的边加入并查集.对于两个符合条件即将合并的连通块增加答案个数num[x]*num[y]*2 .合并:fa[x]=y; num[y]+=num[x]; .最后依次输出结果即可. #include<cstdio> #include<cstring> #include<iostr

hdu 5441 Travel 离线操作+并查集

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5441 题意:给出一张图,有n个点,m条带权边,每次询问给出一个值val,要求删除权值>val的所有边.然后每次询问求多少个点对相连,ab和ba算成两个点对. 思路: 把每条边的权值按照从小到大排序,把每个询问记录下来,按照从小到大排序. 初始图没有边.然后按照询问加入边.对于每个询问,除了已经加入的边,再加入权值比它小的边. 然后用并查集求得每次加一条边后新产生的点对. 用一个数组cnt[i],来记