HDU3938 Portal

来源:互联网 发布:php oa 开源 编辑:程序博客网 时间:2024/06/11 00:50

题意:
有n个点,给你m条无向边,然后有q次询问,每次询问给你一个L,问你对于u到v的所有路径中的每条路径中最长的边的最小值不超过L的这样的点对有多少。
思路:首先考虑每个点对,因为点对之间的决定值只是由最大边来决定。所以贪心一下,边按照从小到大连接,如果之前已经被连接了,那么后面没必要再连接了。
然后每次,询问跑一次是不现实的。嗯,因为大的情况一定包含比它小的情况,所以我们可以离线,排序,处理一次就可以。
判断连接自然就是并查集了。不过注意合并的时候,增加的点数是两棵树的点数的乘积。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int MAXN = 1e4+5;const int inf = 1e9;int n,m,q;struct edge{    int u,v,w;    bool operator < (const edge &a)const    {        return w < a.w;    }}edge[MAXN*5];struct query{    int id;    int key;    bool operator < (const query &a)const    {        return key < a.key;    }}query[MAXN];int ans[MAXN];int pre[MAXN];int findx(int x){    return pre[x] == x? x : pre[x] = findx(pre[x]);}int sum_point[MAXN];int connect(int u,int v){    u = findx(u);    v = findx(v);    int ans = 0;    if(u != v)    {        ans = sum_point[u]*sum_point[v];        pre[v] = pre[u];        sum_point[u] += sum_point[v];    }    return ans;}int main(){    while(~scanf("%d%d%d",&n,&m,&q))    {        for(int i = 0; i < m; ++i)        {            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);        }        for(int i = 0; i < q; ++i)        {            query[i].id = i;            scanf("%d",&query[i].key);        }        sort(edge,edge+m);        sort(query,query+q);        for(int i = 1; i <= n; ++i)        {            pre[i] = i;            sum_point[i] = 1;        }        int j = 0;        int sum = 0;        for(int i = 0; i < q; ++i)        {            while(j < m && edge[j].w <= query[i].key)            {                sum += connect(edge[j].u,edge[j].v);                j++;            }            ans[query[i].id] = sum;        }        for(int i = 0;i < q; ++i)printf("%d\n",ans[i]);    }    return 0;}
原创粉丝点击