• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
dwtfukgv
博客园    首页    新随笔    联系   管理    订阅  订阅
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;
}

 

posted on 2016-08-05 19:28  dwtfukgv  阅读(450)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3