传送门

•题意

  在一个包含 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. <构建之法>13——17章的读后感

    第13章:软件测试 问题:对于这么多种的测试方法,怎么才能最有效的选取? 第14章:质量保证 问题:很多工程师都把大多数时间花在软件质量上.一成不变是无法创新的.如何在保证质量的情况下,又得到创新呢? ...

  2. 基于Spring3 MVC实现基于form表单文件上传

    http://blog.csdn.net/jia20003/article/details/8474374/

  3. 小学四则运算APP 第一个冲刺 第八天

    团队成员:陈淑筠.杨家安.陈曦 团队选题:小学四则运算APP 第一次冲刺阶段时间:11.17~11.27 本次发布的是还未完成的功能二(选择题): ChoiceActivity.java: packa ...

  4. js和JQuery区别

    this.class="btn-default btn-info"; $(this).toggleClass("btn-default btn-info"); ...

  5. python 中的列表(list)

    一.生成一个列表 直接生成 L1 = [1, 2, 3, 4, 5] 列表解析式 >>> L2 = [x for x in range(1, 10, 2)] #从1到10的迭代,步长 ...

  6. HDU 2053 Switch Game

    http://acm.hdu.edu.cn/showproblem.php?pid=2053 Problem Description There are many lamps in a line. A ...

  7. MYSQL两个数据库字符集保持一致问题

    参考这篇文章:https://lzw.me/a/mysql-charset.html 还有一篇官方文档:https://dev.mysql.com/doc/refman/5.7/en/charset. ...

  8. XSS编码与绕过

     XSS编码与绕过 0x00 背景 对于了解web安全的朋友来说,都知道XSS这种漏洞,其危害性不用强调了.一般对于该漏洞的防护有两个思路:一是过滤敏感字符,诸如[<,>,script,' ...

  9. Sqlite,libevent,openssl,mosquito交叉编译

    一.设置交叉编译环境 在makefile所在目录(或源代码根目录)打开终端. 在终端中设置交叉编译所需的临时环境变量(也可写到配置文件中设置为全局环境变量),其中交叉编译工具链的名称和目录需要根据实际 ...

  10. PLSQL 使用ODBC 数据源导入来自SQLSERVER的数据

    1. 创建ODBC数据源 方法: 打开控制命令 Win10 运行->输入 control 查看方式大图标--选择 管理工具 2. 安装了 64位的plsql 应该也选用 64位的ODBC数据源 ...