hdu 5441 (并查集)

题意:给你n个点,m条边构成无向图。q个询问,每次一个值,求有多少条路,路中的边权都小于这个值

a->b 和 b->a算两种

思路:把权值从小到大排序,询问从小到大排序,如果相连则用并查集相连形成联通块

x个点可以形成:x * (x - 1)

如果新增的路使两个联通块和并则数量 增长了:

(num[1]+num[2])×(num[1]+num[2]-1) - num[1] × (num[1]-1) - num[2] ×(num[2]-1)


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
int T,n,m,k;
int num[20005],par[20005],p[20005];

struct node
{
    int u,v,w;
    bool operator<(const node&a)const
    {
        return w < a.w;
    }
} pnode[100005];

struct term
{
    int id,we;
    bool operator<(const term&a)const
    {
        return we<a.we;
    }
} te[20005];

int fin(int x)
{
   return x == par[x]?  x : par[x] = fin(par[x]);
}

void merg(int x,int y)
{
    int x1 = fin(x);
    int x2 = fin(y);
    if(x1 < x2)
    {
        par[x2]= x1;
        num[x1] += num[x2];
    }
    else
    {
        par[x1] = x2;
        num[x2] += num[x1];
    }
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);

        for(int i = 0; i <= n; i++)
        {
            par[i] = i;
            num[i] = 1;
        }

        for(int i = 0; i < m; i++)
            scanf("%d%d%d",&pnode[i].u,&pnode[i].v,&pnode[i].w);
        sort(pnode,pnode+m);

        for(int i = 0; i < k; i++)
        {
            te[i].id = i;
            scanf("%d",&te[i].we);
        }
        sort(te,te+k);
        int tt = 0;
        ll ans = 0;
        for(int i = 0; i < k; i++)
        {
            while(tt < m &&  pnode[tt].w <= te[i].we )
            {
                int u = fin(pnode[tt].u);
                int v = fin(pnode[tt].v);
                tt++;
                if(u == v)
                    continue;
                ans += (num[u]+num[v])*(num[u]+num[v]-1)-num[u]*(num[u]-1) - num[v]*(num[v]-1);
                merg(u,v);
                
            }
            p[te[i].id] = ans;
        }

        for(int i = 0;i <k;i++)
            printf("%d
",p[i]);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Przz/p/5409758.html