zoukankan      html  css  js  c++  java
  • hdu portal(经典)

    这是一道好题,让我又学了一个新的知识,离线算法+并查集

    题意:先给出图,求存在多少路径使得花费T小于L,T的定义是u,v亮点的所有路径的最大边的最小值

    Unfortunately, making a pair of portals will cost min{T} energies. T in a path between point V and point U is the length of the longest edge in the path

    分析:首先将需要询问的Q进行排序,从小到大,因为L的值大的必定包含了L值小的路径。然后将两点各自的集合相乘num[u]*num[v],可以细想一下,假设与u已经合并的点有2个,与v合并的点有3个,那么u,v两集合所能组成的点就是2*3,因为两集合当前存储的边必定都小于T,而且必定都小于T,然后再讲u,v两集合合并,形成新的集合num[u]。对于边的查找,只需要找到小于等于T就可以停止查找,我们可以看一下,当u,v边长为L‘加入,且L'>L,若u,v在一个集合,则新通路为0,因为这两点的路径个数在以前加过了,若u,v在两个集合,则它们之间只有一条通路,可想而知,这条通路的权值为L‘,则无论组成的哪天连通两点的路径其最大边都为L’。

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    const int MAXN= 50010;
    
    struct Edge
    {
        int a,b,l;
    } edge[MAXN];
    
    struct Node
    {
        int t,pos;
    } pl[MAXN/5];
    
    int father[MAXN/5],num[MAXN/5];
    long long temp[MAXN/5];
    
    bool cmp1(Edge a,Edge b)
    {
        return a.l<b.l;
    }
    
    bool cmp2(Node a,Node b)
    {
        return a.t<b.t;
    }
    
    void Make_set(int n)
    {
        for (int i=1; i<=n; i++)
        {
            father[i]=i;
            num[i]=1;
        }
    }
    
    int Find(int x)
    {
        int r=x;
        while(r!=father[r])//这里写错了。。
        {
            r=father[r];
        }
        if(r!=x) father[x]=r;
        return father[x];
    }
    
    int Union(int s1,int s2)
    {
        int x=Find(s1);
        int y=Find(s2);
        if(x==y) return 0;
        long long  t=num[x]*num[y];
        num[x]+=num[y];//祖先代表该集合的总点数
        num[y]=0;//当成为一个集合只需要有个祖先就够了,其他的点为了避免重复均=0
        father[y]=x;
        return t;
    }
    
    int main()
    {
        int n,m,q,i;
        while(scanf("%d%d%d",&n,&m,&q)!=EOF)
        {
            Make_set(n);
            for(i=0; i<m; i++)
            {
                scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].l);
            }
            sort(edge,edge+m,cmp1);
            for(int k=0; k<q; k++)
            {
                scanf("%d",&pl[k].t);
                pl[k].pos=k;
            }
            sort(pl,pl+q,cmp2);
            long long  ans=0;
            int pos=0;
            for(i=0; i<q; i++)
            {
                while(pos<m && edge[pos].l<=pl[i].t)
                {
                    ans+=Union(edge[pos].a,edge[pos].b);
                    pos++;
                }
                temp[pl[i].pos]=ans;
            }
            for(i=0; i<q; i++)
            {
                printf("%lld\n",temp[i]);
            }
        }
        return 0;
    }
  • 相关阅读:
    mysql基础语句
    .opt,frm,.MYD,.MYI文件如何转为.sql文件?
    如何使用phpstudy本地搭建多站点(每个站点对应不同的端口)
    吐槽下微软的vs code编辑器
    补码的两个重要问题
    注意力不集中是因为你没有紧迫感
    弧度与角度的转换公式推导
    ps图层面板上的【透明度】与【填充】的区别
    【ctrl+A】与【ctrl+单击图层缩略图】有什么区别?
    DRF-认证 权限 频率组件
  • 原文地址:https://www.cnblogs.com/zsboy/p/2633267.html
Copyright © 2011-2022 走看看