HDU - 5441 离线带权并查集

Travel
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 5000 Accepted Submission(s): 1611

Problem Description
Jack likes to travel around the world, but he doesn’t like to wait. Now, he is traveling in the Undirected Kingdom. There are n cities and m bidirectional roads connecting the cities. Jack hates waiting too long on the bus, but he can rest at every city. Jack can only stand staying on the bus for a limited time and will go berserk after that. Assuming you know the time it takes to go from one city to another and that the time Jack can stand staying on a bus is x minutes, how many pairs of city (a,b) are there that Jack can travel from city a to b without going berserk?

Input
The first line contains one integer T,T≤5 , which represents the number of test case.

For each test case, the first line consists of three integers n,m and q where n≤20000,m≤100000,q≤5000 . The Undirected Kingdom has n cities and m bidirectional roads, and there are q queries.

Each of the following m lines consists of three integers a,b and d where a,b∈{1,...,n} and d≤100000 . It takes Jack d minutes to travel from city a to city b and vice versa.

Then q lines follow. Each of them is a query consisting of an integer x where x is the time limit before Jack goes berserk.

Output
You should print q lines for each test case. Each of them contains one integer as the number of pair of cities (a,b) which Jack may travel from a to b within the time limit x .

Note that (a,b) and (b,a) are counted as different pairs and a and b must be different cities.

Sample Input
1
5 5 3
2 3 6334
1 5 15724
3 5 5705
4 3 12382
1 3 21726
6000
10000
13000

Sample Output
2
6
12
 

题目描述:输入一个t,测试样例的个数,第二行由三个数n,m,q组成,输入一个n,城市的个数,输入一个m,路线的条数,输入一个q,q个询问,接下来m行由a,b,d组成,其中a,b为城市的编号,d表示两个城市之间的距离,最后q行由一个数x组成,表示能忍受的最长距离输出在有多少个城市对满足Jack不会发疯的条件.注意:每到一个新城市 jack的怒气会回复到0  城市对(1,2)和城市对(2,1)表示两个不同的对.

离线带权并查集(表示完全不知道是什么东西,大佬说什么就是什么)

做法就是把城市按相距的距离从小到大排序一遍,同时询问也从小到大排序一遍

(附上代码):

struct LX
{
    int st;
    int ed;
    int s;
    bool operator < (const LX lx1) const
    {
        return s<lx1.s;
    }
}lx[max_m];
struct Q
{
    int di;
    int id;
    bool operator < (const Q q1) const
    {
        return di<q1.di;
    }
}q[5005];

之后就用并查集把城市之间连起来,用同一个父节点表示

inline void unio(int x,int y)
{
    x=findf(x);y=findf(y);
    if(sum[x]>sum[y])
    {
        sum[x]+=sum[y];
        root[y]=x;
    }
    else
    {
        sum[y]+=sum[x];
        root[x]=y;
    }
}

然后按询问从小到大遍历一遍所有联通的城市(就算城市不止由一棵树构成,或者说就算一棵树上的城市之间的距离大于jack的暴怒值,jack也可以在距离小于暴怒值的城市间来回,就是说你要找到所有城市距离小于暴怒值的个数)(终于说清了~~~~~~~~~~)

当你查询到不同的树时可到达城市对的个数增加了sum[1]*sum[2]个(其实是sum[1]*sum[2]*2个)但我们先记为增加了这么多同时把这两棵数合并成一棵,然后神奇操作来了

平时我们合并的话可能是随便把一个当成父节点让另一个变成他的子节点,在这里我们让更大的那个变成父节点,另一个变成子节点这样的话父节点的儿子会越变越多,这样在后面合并树的时候会显得很方便直接,之后只需要把每一个询问遍历得到的答案按询问的顺序存在一个数组里面就好了,最后按询问的顺序输出就好了

注意之前我们只是按城市编号从小到大遍历了一遍,所以对于每一个询问只给出了一半的坐标.所以输出的时候需要乘一个2.在这个题目里面输出ans[a]*2是会超时的,需要用到位运算输出ans[a]<<1,不然会超时的(我就超时了几遍差点心态炸了)

AC代码:

#include <iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int max_m=100000+5;
const int max_n=20000+5;
struct LX
{
    int st;
    int ed;
    int s;
    bool operator < (const LX lx1) const
    {
        return s<lx1.s;
    }
}lx[max_m];
struct Q
{
    int di;
    int id;
    bool operator < (const Q q1) const
    {
        return di<q1.di;
    }
}q[5005];
int root[max_n];
int sum[max_n];
int ans[5005];
int n,m,qt;
int findf(int x)
{
    return x==root[x]?x:root[x]=findf(root[x]);
}
inline void unio(int x,int y)
{
    x=findf(x);y=findf(y);
    if(sum[x]>sum[y])
    {
        sum[x]+=sum[y];
        root[y]=x;
    }
    else
    {
        sum[y]+=sum[x];
        root[x]=y;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {

        scanf("%d%d%d",&n,&m,&qt);
        for(int m1=1;m1<=m;m1++)
        {
            scanf("%d%d%d",&lx[m1].st,&lx[m1].ed,&lx[m1].s);
        }
        sort(lx+1,lx+m+1);
        for(int q1=1;q1<=qt;q1++)
        {
            scanf("%d",&q[q1].di);
            q[q1].id=q1;
        }
        sort(q+1,q+1+qt);
        for(int n1=1;n1<=n;n1++)
        {
            root[n1]=n1;
            sum[n1]=1;
        }
        int j=0;
        int m1=1,q1=1;
        for(;q1<=qt;q1++)
        {
            for(;m1<=m&&lx[m1].s<=q[q1].di;m1++)
            {
                if(findf(lx[m1].st)==findf(lx[m1].ed))
                {
                    continue;
                }
                j=j+sum[findf(lx[m1].st)]*sum[findf(lx[m1].ed)];
                unio(lx[m1].st,lx[m1].ed);
            }
            ans[q[q1].id]=j;
        }
        for(int q1=1;q1<=qt;q1++)
        {
            printf("%d\n",ans[q1]<<1);
        }
    }
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值