传送门

•题意

  在一个包含 n 个节点 m 条边的森林中;

  有 q 次询问,每次询问求解两点间的最短距离;

  如果这两点不联通,输出 "Not connected";

•题解1

  树上任意两点间的最短距离就是最近公共祖先分别到这两点的距离和;

  那么这个问题就被转化成了LCA问题。

  因为有多棵树,所以,对于每棵树,都提前预处理出 $dis,dep$;

  并通过并查集判断询问的两点是否联通;

•Code

 #include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e4+; int n,m,q;
int num;
int head[maxn];
struct Edge
{
int to;
ll w;
int next;
}G[maxn<<];
void addEdge(int u,int v,ll w)
{
G[num]={v,w,head[u]};
head[u]=num++;
}
vector<int >V[maxn];
/**
fa[i][j]:节点j沿着其父结点向上走2^i步所到的节点(超过根节点时记为-1)
///dis[i]:节点i的与根节点的距离
///dep[i]:节点i的深度,根节点深度为0
*/
struct LCA
{
int fa[][maxn];
ll dis[maxn];
ll dep[maxn];
void DFS(int u,int f,ll Dis,ll Dep)
{
fa[][u]=f;///节点u向上走2^0步来到的节点便是其父节点
dis[u]=Dis;
dep[u]=Dep;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
ll w=G[i].w;
if(v != f)
DFS(v,u,Dis+w,Dep+);
}
}
void Init()
{
for(int i=;i <= n;++i)
{
if(V[i].empty())
continue;
///预处理出每棵树的dis,dep,fa
DFS(V[i][],-,,);
for(int k=;k <= ;++k)
for(int j=;j < V[i].size();++j)
{
int u=V[i][j];
if(fa[k-][u] == -)
fa[k][u]=-;
else
fa[k][u]=fa[k-][fa[k-][u]];
}
}
}
int lca(int u,int v)///返回u,v的最近公共祖先
{
if(dep[u] > dep[v])
swap(u,v); for(int i=;i <= ;++i)
if((dep[v]-dep[u])>>i&)
v=fa[i][v];
if(u == v)
return u; for(int i=;i >= ;--i)
if(fa[i][u] != fa[i][v])
{
u=fa[i][u];
v=fa[i][v];
}
return fa[][u];
}
}_lca;
struct Set
{
int fa[maxn];
void Init()
{
for(int i=;i <= n;++i)
fa[i]=i;
}
int Find(int x)
{
return x == fa[x] ? x:fa[x]=Find(fa[x]);
}
void Union(int x,int y)
{
x=Find(x);
y=Find(y);
if(x != y)
fa[x]=y;
}
}_set;
void Solve()
{
for(int i=;i <= n;++i)///将属于同一颗树的节点存在_set.fa[i]中
V[_set.Find(i)].push_back(i);///并查集查找i的祖先节点用Find()
_lca.Init(); while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
if(_set.Find(u) != _set.Find(v))///判断u,v是否属于同一棵树用Find()
puts("Not connected");
else
{
int x=_lca.lca(u,v);
ll ans=_lca.dis[u]+_lca.dis[v]-*_lca.dis[x];
printf("%lld\n",ans);
}
}
}
void Init()
{
num=;
for(int i=;i <= n;++i)
{
head[i]=-;
V[i].clear();
}
_set.Init();
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\C++WorkSpace\\in&&out\\contest","r",stdin);
while(~scanf("%d%d%d",&n,&m,&q))
{
Init();
for(int i=;i <= m;++i)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addEdge(u,v,w);
addEdge(v,u,w);
_set.Union(u,v);
}
Solve();
}
return ;
}

基于二分的LCA

•题解2

  通过添加虚点将森林转化成一棵树;

  并以添加的虚点作为这棵树的根节点;

  对于询问操作,如果询问的两点的 $LCA$ 为虚点,那么这两点在原森林中不连通;

  这么做的话,只需处理一棵树的 $dis,dep,fa$;

•Code

 #include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e4+; int n,m,q;
int num;
int head[maxn];
struct Edge
{
int to;
ll w;
int next;
}G[maxn<<];
void addEdge(int u,int v,ll w)
{
G[num]={v,w,head[u]};
head[u]=num++;
}
/**
fa[i][j]:节点j沿着其父结点向上走2^i步所到的节点(超过根节点时记为-1)
///dis[i]:节点i的与根节点的距离
///dep[i]:节点i的深度,根节点深度为0
*/
struct LCA
{
int fa[][maxn];
ll dis[maxn];
ll dep[maxn];
void DFS(int u,int f,ll Dis,ll Dep)
{
fa[][u]=f;///节点u向上走2^0步来到的节点便是其父节点
dis[u]=Dis;
dep[u]=Dep;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
ll w=G[i].w;
if(v != f)
DFS(v,u,Dis+w,Dep+);
}
}
void Init()
{
DFS(n+,-,,);
for(int k=;k <= ;++k)
for(int u=;u <= n+;++u)
if(fa[k-][u] == -)
fa[k][u]=-;
else
fa[k][u]=fa[k-][fa[k-][u]];
}
int lca(int u,int v)///返回u,v的最近公共祖先
{
if(dep[u] > dep[v])
swap(u,v); for(int i=;i <= ;++i)
if((dep[v]-dep[u])>>i&)
v=fa[i][v];
if(u == v)
return u; for(int i=;i >= ;--i)
if(fa[i][u] != fa[i][v])
{
u=fa[i][u];
v=fa[i][v];
}
return fa[][u];
}
}_lca;
struct Set
{
int fa[maxn];
void Init()
{
for(int i=;i <= n+;++i)
fa[i]=i;
}
int Find(int x)
{
return x == fa[x] ? x:fa[x]=Find(fa[x]);
}
void Union(int x,int y)
{
x=Find(x);
y=Find(y);
if(x != y)
fa[x]=y;
}
}_set;
void Solve()
{
_lca.Init(); while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
int x=_lca.lca(u,v);
if(x == n+)
puts("Not connected");
else
{
ll ans=_lca.dis[u]+_lca.dis[v]-*_lca.dis[x];
printf("%lld\n",ans);
}
}
}
bool vis[maxn];
void Init()
{
num=;
for(int i=;i <= n+;++i)
{
head[i]=-;
vis[i]=false;
}
_set.Init();
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\C++WorkSpace\\in&&out\\contest","r",stdin);
while(~scanf("%d%d%d",&n,&m,&q))
{
Init();
for(int i=;i <= m;++i)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addEdge(u,v,w);
addEdge(v,u,w);
_set.Union(u,v);
}
///定义虚节点 n+1
///将节点n+1与连接每棵树的某个节点
///每棵树只有一个节点与节点n+1相连,边仅加一次
for(int i=;i <= n;++i)
if(!vis[_set.Find(i)])///此处用Find(i)而不是用fa[i]
{
addEdge(n+,_set.Find(i),);
vis[_set.Find(i)]=true;
} Solve();
}
return ;
}

基于二分的LCA

hdu 2874(裸LCA)的更多相关文章

  1. hdu 2586(裸LCA)

    传送门 题意: 某村庄有n个小屋,n-1条道路连接着n个小屋(无环),求村庄A到村庄B的距离,要求是经过任一村庄不超过一次. 题解: 求出 lca = LCA(u,v) , 然后答案便是dist[u] ...

  2. hdu 2874(LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 思路:近乎纯裸的LCA,只是题目给出的是森林,就要判断是否都在同一颗树上,这里我们只需判断两个子 ...

  3. HDU 2874 Connections between cities (LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 题意是给你n个点,m条边(无向),q个询问.接下来m行,每行两个点一个边权,而且这个图不能有环路 ...

  4. HDU 2874 Connections between cities(LCA离线算法实现)

    http://acm.hdu.edu.cn/showproblem.php?pid=2874 题意: 求两个城市之间的距离. 思路: LCA题,注意原图可能不连通. 如果不了解离线算法的话,可以看我之 ...

  5. HDU 2874 Connections between cities(LCA(离线、在线)求树上距离+森林)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 题目大意:给出n个点,m条边,q个询问,每次询问(u,v)的最短距离,若(u,v)不连通即不在同 ...

  6. HDU 2874 Connections between cities(LCA+并查集)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=2874 [题目大意] 有n个村庄,m条路,不存在环,有q个询问,问两个村庄是否可达, 如果可达则输出 ...

  7. 【HDU 2874】Connections between cities(LCA)

    dfs找出所有节点所在树及到树根的距离及深度及父亲. i和j在一棵树上,则最短路为dis[i]+dis[j]-dis[LCA(i,j)]*2. #include <cstring> #in ...

  8. hdu 2874 Connections between cities [LCA] (lca->rmq)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  9. HDU 2874 Connections between cities(LCA Tarjan)

    Connections between cities [题目链接]Connections between cities [题目类型]LCA Tarjan &题意: 输入一个森林,总节点不超过N ...

随机推荐

  1. Jenkins部署Python项目实战

    一.背景 我们工作中常用Jenkins部署Java代码,因其灵活的插件特性,例如jdk,maven,ant等使得java项目编译后上线部署一气呵成,同样对于脚本语言类型如Python上线部署,利用Je ...

  2. 微信扫描 安卓和ios 不会

    wx.ready(function(){ $('#scan').click(function(){ wx.scanQRCode({ needResult: 1, // 默认为0,扫描结果由微信处理,1 ...

  3. 个人博客作业_week7

    心得 在为期将近一个月的团队编程中,给我感受最深的是敏捷开发和团队中队员之间的互补. 在最初的软件开发中,由于以前没有这方面的经验,所以并没有很大的进展.在慢慢过度中,我们找到了自己的节奏感,大家各自 ...

  4. javaBean中 字符串 转 date 类型转换

    1-----创建javabean 代码如下 package BeanUtils; import java.util.Date; public class Admin { private String ...

  5. github链接

    github链接:https://github.com/bjing123     test1:https://github.com/bjing123/test-/blob/master/test1.t ...

  6. 开发中CollectionUtils处理集合

    1.org.apache.commons.collections.CollectionUtils; 使用这个工具类,帮我们处理一些集合的操作,非常方便 //取并集public void testUni ...

  7. ESXi 更新补丁 暂时未测试 等有时间尝试一下.

    下载地址: https://my.vmware.com/group/vmware/patch 使用操作图: 选择相应的zip包下载即可 更新方式: 命令方式升级ESXi主机补丁包 1.进入VMware ...

  8. FuelPHP 系列(六) ------ CURD 增删改查

    一.create $article = new Model_Article(); // 或 $article = Model_Article::forge(); // 保存数据,返回新增数据 id $ ...

  9. HAProxy+keepalived+MySQL 实现MHA中slave集群负载均衡的高可用

    HAProxy+keepalived+MySQL实现MHA中slave集群的负载均衡的高可用 Ip地址划分: 240    mysql_b2 242    mysql_b1 247    haprox ...

  10. mysql 8.0,运行springboot项目配置:

    1.修改pom.xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connecto ...