Loading

[HDU - 5441]Travel

大意:告诉你有n个点  m个边的无向图  

然后问有多少点对  他们的路径上节点之间的距离都少于 x

思路:

并查集

离线处理。将边权值按从小到大排序,查询标号后按照从小到大排序。对于每次查询,依次将比当前查询值小的边加入并查集。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int t;
int n,m,q;
struct  path
{
    int starts;
    int ends;
    int weight;
     bool operator <(const path &x)const{
      return weight<x.weight;
     }
}P[100000 + 5];
struct input
{
    int id;
    int limit;
    bool operator <(const input &x)const{
      return limit < x.limit;
     }
}L[100000 + 5];
long long ans[5000 + 5];
int father[20000 + 5];
int cnt[20000 + 5];

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

void init()
{
    for (int j = 1; j <= n; j++)
    {
        father[j] = j;
        cnt[j] = 1;
    }
    memset(ans,0,sizeof(ans));
}
int main()
{
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d%d", &n, &m, &q);
        for (int i = 0; i < m; i++)
            scanf("%d %d %d", &P[i].starts, &P[i].ends, &P[i].weight);
        sort(P, P + m);
        for (int i = 0; i < q; i++)
        {
            L[i].id = i;
            scanf("%d", &L[i].limit);
        }
        sort(L, L + q);
        init();
        int cur = 0;
        long long sum = 0;
        for (int i = 0; i < q; i++)
        {
            while (cur < m && L[i].limit >= P[cur].weight)
            {
                int fstarts = Find(P[cur].starts);
                int fends = Find(P[cur].ends);
                if(fstarts != fends)
                {
                    sum += cnt[fstarts] * cnt[fends]; //将总联通块合并,再将合并之前的已有的减去,得到的算式化简得
                    father[fends] = fstarts;
                    cnt[fstarts] += cnt[fends];
                }
                cur++;
            }
            ans[L[i].id] = sum;
        }
        for(int i = 0; i < q; i++)
            printf("%lld\n", 2 * ans[i]);
}
return 0;
}

 

posted @ 2019-08-20 21:39  ViKyanite  阅读(108)  评论(0编辑  收藏  举报