hdu 5441 Travel(帶權並查集)

Problem 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 bidirectional roads connecting the cities. Jack hates waiting too long on the bus, but he can rest at every city. Jack can only stand staying on the bus for a limited time and will go berserk after that. Assuming you know the time it takes to go from one city to another and that the time Jack can stand staying on a bus is x minutes, how many pairs of city (a,b) are there that Jack can travel from city a to b without going berserk?
 

Input
The first line contains one integer T,T5, which represents the number of test case.

For each test case, the first line consists of three integers n,m and q where n20000,m100000,q5000. The Undirected Kingdom has n cities and mbidirectional roads, and there are q queries.

Each of the following m lines consists of three integers a,b and d where a,b{1,...,n} and d100000. It takes Jack d minutes to travel from city a to city band vice versa.

Then q lines follow. Each of them is a query consisting of an integer x where x is the time limit before Jack goes berserk.

 

Output
You should print q lines for each test case. Each of them contains one integer as the number of pair of cities (a,b) which Jack may travel from a to b within the time limit x.

Note that (a,b) and (b,a) are counted as different pairs and a and b must be different cities.
 

Sample Input
1 5 5 3 2 3 6334 1 5 15724 3 5 5705 4 3 12382 1 3 21726 6000 10000 13000
 

Sample Output
2 6 12

solution:

有一個n個點的無向圖,給出m條邊的邊權,給出q次詢問,每次給出一個值,求用到所有邊權不大於這個值的邊的情況下,能夠互相到達的點對的個數。剛開始以爲是最短路變形,但後來發現可以用帶權並查集做,把查詢讀入後從小到大排序,然後對於每次查詢,我用並查集維護邊權不大於這個值的每個聯通塊中節點個數,若可以合併u,v,且num[i]代表以i爲根的聯通塊的節點數,則要加上(num[u] + num[v])*(num[u] + num[v] - 1) - num[u] * (num[u] - 1) - num[v] * (num[v] - 1),因爲在次之前我們已經累加過num[i] * (num[i] - 1)。在每次合併時,我們應該選準壓縮路徑的方向,我每次都是把節點編號大的插在節點編號小的下面。

詳細看代碼~

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 20500;
int fa[maxn], num[maxn],ans[maxn];
int n;
struct edge{
    int u, v, w;
    bool operator <(const edge &x)const
    {
        return w < x.w;
    }
}e[maxn*5];
struct Query
{
    int id, x;
    bool operator <(const Query &a)const
    {
        return x < a.x;
    }
}query[maxn];
void init()
{
    for (int i = 1; i <= n; i++)
    {
        num[i] = 1; 
        fa[i] = i;
    }
}
int find(int x)
{
    if (fa[x] == x)return x;
    return fa[x] = find(fa[x]);
}
void _union(int x, int y)
{
    x = find(x); y = find(y);
    if (x > y)swap(x, y);
    fa[y] = x;
    num[x] += num[y];
}
int main()
{
    int t,m,q;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d%d", &n, &m, &q);
        init();
        for (int i = 0; i <m; i++)
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
        sort(e, e + m);
        for (int i = 0; i < q; i++)
        {
            query[i].id = i;
            scanf("%d", &query[i].x);
        }
        sort(query, query + q);
        int j = 0, tmp = 0;
        for (int i = 0; i < q; i++)
        {
            while (j < m&&e[j].w <= query[i].x)
            {
                int u = find(e[j].u), v = find(e[j].v);
                j++;
                if (u == v)continue;
                tmp += (num[u] + num[v])*(num[u] + num[v] - 1) - num[u] * (num[u] - 1) - num[v] * (num[v] - 1);
                _union(u, v);
            }
            ans[query[i].id] = tmp;
        }
        for (int i = 0; i < q; i++)
            printf("%d\n", ans[i]);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章