hdu5441

题目描述:

在一张图中求出有多少对这样的点满足a关系?

a:相连并且路径上直接相连的两个点的边的权值小于给定的某个值,假设是x

因为询问不确定,所以可以先读取询问操作,按照我们想要的方式回答,然后按照原始顺序输出。

相连并且直接相连的每条边的权值小于x的点为一个集合,在这个集合中满足条件的点对有A(2,5)

假设给定的x大于这张图中所有边的权值,那么满足条件的点对有A(2,n)种;

但是x不确定,所以可以先给x从小到大排序,因为大x的答案肯定包含小x的答案,

然后图中边的权值从小到大排序,由x将边分块回答,采用并查集将一条边相连的点合并。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 105000
struct Edge
{
    int from,to,dist;
}edge[maxn];
int n,m,q;
int answer[maxn];
struct node
{
    int d,id;
}que[5500];
bool cmp1(Edge a,Edge b)
{
    return a.dist<b.dist;
}
bool cmp2(node a,node b)
{
    return a.d<b.d;
}
int fa[maxn];
int Size[maxn];
void init()
{
     for(int i=1;i<=n;i++)
       {
           fa[i]=i;      //代表每个元素的父亲节点
           Size[i]=1;    //代表集合中有多少元素
       }
}

int Find(int x)
{
   if(x!=fa[x])   fa[x]=Find(fa[x]);
   return fa[x];
}
void solve()
{
    int ans=0;
    int j=1;
    for(int i=1;i<=q;i++)
    {
       for(;edge[j].dist<=que[i].d ;j++)
       {
            int from,to;
            from=edge[j].from;
            to=edge[j].to;
            if(from==to)
              continue;
            int t1,t2;
            t1=Find(from);
            t2=Find(to);
            if(t1==t2)  //如果在一个集合,就不用合并
                continue;
            ans+=2*Size[t1]*Size[t2];
            fa[t2]=t1;
            Size[t1]+=Size[t2];
       }
       answer[que[i].id]=ans;
    }
    for(int i=1;i<=q;i++)
        printf("%d
",answer[i]);
}
int main()
{
    //freopen("test.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&q);
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].dist);
        }
        for(int i=1;i<=q;i++)
        {
            scanf("%d",&que[i].d);
            que[i].id=i;
        }
        sort(edge+1,edge+m+1,cmp1);
        sort(que+1,que+q+1,cmp2);
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xianbin7/p/4817102.html