传送门

•题意

  在一个包含 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. ACM-ICPC 2017 Asia Urumqi:A. Coins(DP)

    挺不错的概率DP,看似基础,实则很考验扎实的功底 这题很明显是个DP,为什么???找规律或者算组合数这种概率,N不可能给的这么友善... 因为DP一般都要在支持N^2操作嘛. 稍微理解一下,这DP[i ...

  2. 网络:OSPF理解

    OSPF(开放最短路径优先)协议使用Dijkstra算法,常见的版本有:OSPFv2.OSPFv3等.以下主要介绍OSPFv2,OSPFv3是面向IPv6的且不兼容IPv4. 1.工作过程: 1)每台 ...

  3. EnglishGame

    https://github.com/zhangxue520/EnglishGame/blob/master/EnglishGame <程序设计实践I> 题目:       打字训练测试软 ...

  4. Android Studio下创建menu布局文件

    一.问题: android studio项目中没有看到menu文件夹: 在android studio项目中想要添加menu布局文件,一开始我的做法是:直接在res文件夹右键选择xml文件来添加,如下 ...

  5. 【Deep Hash】CNNH

    [AAAI 2014] Supervised Hashing via Image Representation Learning [paper] [code] Rongkai Xia , Yan Pa ...

  6. throws和throw抛出异常的使用规则

    一直对java中的throws和throw不太理解.最近一直在查这两个方面的资料,算是能明白一点吧.如果我下面的观点哪有不对,希望指出来,我加以改进.         throw:(针对对象的做法) ...

  7. Jenkins 安装简记录

    下载jenkins.war,放入tomcat 启动tomcat,如果console报错java.lang.OutOfMemoryError: PermGen space,则修改startup.bat( ...

  8. Laravel 5.5 文档 ] 快速入门 —— 安装配置篇

    服务器要求 Laravel 框架对PHP版本和扩展有一定要求,不过这些要求 Laravel Homestead 都已经满足了,不过如果你没有使用 Homestead 的话(那真是一件很遗憾的事情),有 ...

  9. Jquery 组 tbale表格隔行变色

    <!DOCTYPE html><html lang="zh-cn"><head> <meta charset="utf-8&qu ...

  10. NodeJS 学习记录

    这里是我学习NodeJs的学习记录 URL:网址解析的好帮手 URL,URI 首先,URI是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源.而URL是u ...