hdu 3938(离线并查集)

  1. /* 
  2. 离线并查集,边按小到大排序,询问也按小到大排序; 
  3. 对于询问x,答案就是询问x-1的值加上询问x-1的L1和询问x的L2之间的边合并带来的值 
  4. 对于一条属于L1和L2之间的边,如果端点u,v在一个集合中,忽略,否则新开的路是u 
  5. 所在集合的大小乘上v所在集合的大小 
  6. */  
  7. #include <cstdio>  
    #include <cstring>  
    #include <algorithm>  
    using namespace std;  
    struct EDGE  
    {  
        int u, v, val;  
    }edge[50000 + 1234];  
    struct QUE  
    {  
        int id, val;  
    }l[10000 + 123];  
    int n, m, q;  
    int p[10000 + 123];  
    int num[10000 + 123];  
    int cou[10000 + 123];  
    bool cmp(EDGE x, EDGE y)  
    {  
        return x.val < y.val;  
    }  
    bool cmp2(QUE x, QUE y)  
    {  
        return x.val < y.val;  
    }  
    void init()  
    {  
        for(int i = 1; i <= n; i++)  
        {  
            p[i] = i;  
            num[i] = 1;  
        }  
    }  
    int find(int k)  
    {  
        if(k != p[k])  p[k] = find(p[k]);  
        return p[k];  
    }  
    int Union(int a, int b)  
    {  
        a = find(a);  
        b = find(b);  
        if(a == b) return 0;  
        int t = num[a] * num[b];  
        p[b] = a;  
        num[a] += num[b];  
        num[b] = 0;  
        return t;  
    }  
    int main()  
    {  
        while(scanf("%d%d%d", &n, &m, &q) != EOF)  
        {  
            for(int i = 0; i < m; i++)  scanf("%d%d%d",&edge[i].u, &edge[i].v, &edge[i].val);  
            sort(edge, edge + m, cmp);  
            for(int i = 0; i < q; i++)  
            {  
                scanf("%d", &l[i].val);  
                l[i].id = i;  
            }  
            sort(l, l + q, cmp2);  
      
            init();  
            int begin = 0;  
            int ans = 0;  
            for(int i = 0; i < q; i++)  
            {  
                while(edge[begin].val <= l[i].val && begin < m)  
                {  
      
                    ans += Union(edge[begin].u, edge[begin].v);  
                    begin++;  
                }  
                cou[l[i].id] = ans;  
            }  
      
            for(int i = 0; i < q; i++)  
            printf("%d\n", cou[i]);  
        }  
        return 0;  
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值