離線+帶權並查集 hdoj3938 Portal

題目傳送門: http://acm.hdu.edu.cn/showproblem.php?pid=3938

題目的題意有些不清楚,看了discuss才明白。定義圖上一條路徑的cost爲路徑中所有邊權中最大的那個。對於給定的圖,回答當最大的路徑長度爲l的時候,最多可以有多少頂點對是可及的。

按照Kruskal的思路,按邊權從小到大連接頂點,每次相連,如果減少一個連通分量,那麼可及頂點對就會增大,增大的個數就是原來兩個連通分量頂點個數的乘積,不斷累加就可以得到對於不同的l,一共有多少頂點對。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 5e4 + 5;
const int N = 1e4 + 5;
int father[N], sum[N], ans[N];
int n, m, t;
struct edge {
    int u, v, w;
} e[M];
struct query {
    int id, l;
} q[N];
bool cmp(const edge &e1, const edge &e2)
{
    return e1.w < e2.w;
}
bool cmp1(const query &q1, const query &q2)
{
    return q1.l < q2.l;
}
int find(int x)
{
    while (x != father[x]) {
        father[x] = father[father[x]];
        x = father[x];
    }
    return x;
}
int merge(int x, int y)
{
    x = find(x);
    y = find(y);
    if (x != y) {
        father[y] = x;
        sum[x] += sum[y];
        return (sum[x] - sum[y]) * sum[y];
    } else return 0;
}
void init(void)
{
    for (int i = 1; i <= n; i ++) {
        sum[i] = 1;
        father[i] = i;
    }
}
int main()
{
    while (~scanf("%d%d%d", &n, &m, &t)) {
        init();
        for (int i = 1; i <= m; i ++) {
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
        }
        sort(e + 1, e + 1 + m, cmp);
        for (int i = 1; i <= t; i ++) {
            scanf("%d",&q[i].l);
            q[i].id = i;
        }
        sort(q + 1, q + 1 + t, cmp1);
        int cnt = 0, j = 1;
        for (int i = 1; i <= t; i ++) {
            while (j <= m && e[j].w <= q[i].l) {
                cnt += merge(e[j].u, e[j].v);
                ++ j;
            }
            ans[q[i].id] = cnt;
        }
        for (int i = 1; i <= t; i ++) {
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章