题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

在线版本:

在线方法的思路很简单,就是倍增。一遍dfs得到每个节点的父亲,以及每个点的深度。然后用dp得出每个节点向上跳2^k步到达的节点。

那么对于一个查询u,v,不妨设depth[u]>=depth[v],先让u向上跳depth[u]-depth[v]步,跳的方法就是直接用数字的二进制表示跳。

然后现在u和v都在同一深度上了,再二分找向上共同的祖先,就可以二分出lca了。复杂度nlogn预处理+qlogn查询。

#include<bits/stdc++.h>
using namespace std; int read()
{
char c=getchar();
while (!isdigit(c)) c=getchar();
int x=;
while (isdigit(c))
{
x=x*+c-'';
c=getchar();
}
return x;
} const int maxn=;
const int maxm=maxn*;
int head[maxn];
struct Edge
{
int u,v,w,nxt;
}edge[maxm];
int tot; void init()
{
tot=;
memset(head,-,sizeof(head));
} void addedge(int u,int v,int w)
{
++tot;
edge[tot].u=u;
edge[tot].v=v;
edge[tot].w=w;
edge[tot].nxt=head[u];
head[u]=tot;
} int dep[maxn];
int pa[maxn];
int dis[maxn]; void dfs(int u,int f,int de,int d)
{
pa[u]=f;
dep[u]=de;
dis[u]=d;
for (int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].v;
int w=edge[i].w;
if (v!=f)
{
dfs(v,u,de+,d+w);
}
}
} int fa[maxn][]; int getlca(int u,int v)
{
if (dep[u]<dep[v]) swap(u,v);
int jump=dep[u]-dep[v];
for (int i=;i<;i++)
{
if (jump&) u=fa[u][i];
jump>>=;
}
for (int i=;i>=;i--)
{
if (fa[u][i]!=fa[v][i])
{
u=fa[u][i];
v=fa[v][i];
}
}
if (u!=v) return pa[u];
else return u;
} int main()
{
int t;
t=read();
while (t--)
{
init();
int n,q;
n=read();
q=read();
for (int i=;i<n-;i++)
{
int u,v,w;
u=read();
v=read();
w=read();
addedge(u,v,w);
addedge(v,u,w);
}
dfs(,,,);
for (int i=;i<=n;i++) fa[i][]=pa[i];
for (int i=;i<;i++)
for (int j=;j<=n;j++)
fa[j][i]=fa[fa[j][i-]][i-];
while (q--)
{
int u,v;
u=read();
v=read();
int lca=getlca(u,v);
int ans=dis[u]+dis[v]-*dis[lca];
printf("%d\n",ans);
}
}
return ;
}

离线版本:

离线版本复杂度低,所以有时候还是很有必要会的。(有一次比赛在线的做法就被卡常了)

离线版本的思路是:每个点都把与它有关的查询放进它的那个vector里,然后对这棵树进行一次dfs,在dfs的过程中直接得出所有查询的答案,复杂度是O(n+q)。

具体来说,假设有一个查询u,v,当遍历到u的时候,如果v还没有遍历,就先不管这个查询;如果v已经遍历过了,那就处理这个查询,那么这个查询的结果是什么呢?结果就是v向上一直找,找到深度最浅的那个已经遍历过并且当前正在考虑这棵子树的节点,就是u和v的lca。这是用到了dfs的中序遍历性质,很难表达清楚,可以通过想象感觉一下。那么怎么得到v向上一直找,找到最浅的那个已经遍历过的节点呢?并查集。具体可以参照代码,这个感觉真的只能通过想象感觉出来,确实很难表述。

#include<bits/stdc++.h>
using namespace std; int read()
{
char c=getchar();
while (!isdigit(c)) c=getchar();
int x=;
while (isdigit(c))
{
x=x*+c-'';
c=getchar();
}
return x;
} const int maxn=;
const int maxm=maxn*;
int head[maxn];
struct Edge
{
int u,v,w,nxt;
}edge[maxm];
int tot; void init()
{
tot=;
memset(head,-,sizeof(head));
} void addedge(int u,int v,int w)
{
++tot;
edge[tot].u=u;
edge[tot].v=v;
edge[tot].w=w;
edge[tot].nxt=head[u];
head[u]=tot;
} vector< pair<int,int> > Q[maxn];
bool vis[maxn];
int fa[maxn];
int ans[];
int dis[maxn]; void addquery(int u,int v,int id)
{
Q[u].push_back(make_pair(v,id));
Q[v].push_back(make_pair(u,id));
} int findfa(int x)
{
if (fa[x]==x) return x;
return fa[x]=findfa(fa[x]);
} int n,q; void dfs(int u,int d)
{
dis[u]=d;
vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].v;
int w=edge[i].w;
if (!vis[v])
{
dfs(v,d+w);
fa[v]=u;
}
}
for (int i=;i<Q[u].size();i++)
{
int v=Q[u][i].first;
int id=Q[u][i].second;
if (vis[v]) ans[id]=dis[u]+dis[v]-*dis[findfa(v)];
}
} int main()
{
int t;
t=read();
while (t--)
{
init();
n=read();
q=read();
for (int i=;i<n-;i++)
{
int u,v,w;
u=read();
v=read();
w=read();
addedge(u,v,w);
addedge(v,u,w);
}
for (int i=;i<maxn;i++) Q[i].clear();
memset(vis,false,sizeof(vis));
for (int i=;i<=n;i++) fa[i]=i;
for (int i=;i<q;i++)
{
int u,v;
u=read();
v=read();
addquery(u,v,i);
}
dfs(,);
for (int i=;i<q;i++) printf("%d\n",ans[i]);
}
return ;
}

[hdu 2586]lca模板题(在线+离线两种版本)的更多相关文章

  1. HDU 2586 (LCA模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2586 题目大意:在一个无向树上,求一条链权和. 解题思路: 0 | 1 /   \ 2      3 ...

  2. hdu - 2586 (LCA板子题)

    传送门 (这次的英文题面要比上一个容易看多了) (英语蒟蒻的卑微) 又是一个很裸的LCA题 (显然,这次不太容易打暴力咧) (但听说还是有大佬用dfs直接a掉了) 正好 趁这个机会复习一下LCA 这里 ...

  3. hdu 2586 How far away?(LCA模板题+离线tarjan算法)

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. POJ 1470 Closest Common Ancestors (模板题)(Tarjan离线)【LCA】

    <题目链接> 题目大意:给你一棵树,然后进行q次询问,然后要你统计这q次询问中指定的两个节点最近公共祖先出现的次数. 解题分析:LCA模板题,下面用的是离线Tarjan来解决.并且为了代码 ...

  5. 【转载】pygame安装与两种版本的Python兼容问题

    在开始学习游戏编程之前,我们先来安装下pygame和python3.2.5 参考园友: http://www.cnblogs.com/hongten/p/hongten_pygame_install. ...

  6. HDU - 2586 How far away ?(LCA模板题)

    HDU - 2586 How far away ? Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & ...

  7. HDU 2586——How far away ?——————【LCA模板题】

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  8. HDU2586 How far away ?(LCA模板题)

    题目链接:传送门 题意: 给定一棵树,求两个点之间的距离. 分析: LCA 的模板题目 ans = dis[u]+dis[v] - 2*dis[lca(u,v)]; 在线算法:详细解说 传送门 代码例 ...

  9. HDU 2586 LCA

    题目大意: 多点形成一棵树,树上边有权值,给出一堆询问,求出每个询问中两个点的距离 这里求两个点的距离可以直接理解为求出两个点到根节点的权值之和,再减去2倍的最近公共祖先到根节点的距离 这是自己第一道 ...

随机推荐

  1. Python学习 :深浅拷贝

    深浅拷贝 一.浅拷贝 只拷贝第一层数据(不可变的数据类型),并创建新的内存空间进行储蓄,例如:字符串.整型.布尔 除了字符串以及整型,复杂的数据类型都使用一个共享的内存空间,例如:列表 列表使用的是同 ...

  2. 5.Python的语言特点

    前言   Python有哪些语言特点?可以列出的特点很多,例如,<Python核心编程>第二版列出了十多条特点.本文的三个特点是笔者学习Python的体会,其他特点有体会之后再写,笔者是这 ...

  3. ctf题目writeup(6)

    2019.2.2 依旧是bugku上面的题目,地址:https://ctf.bugku.com/challenges 1. 解压后是60多个out.zip,都是真加密,里面都是1kb的data.txt ...

  4. R语言学习笔记(十三):零碎知识点(36-40)

    36--diag() 如果它的参数是一个矩阵,它返回的是一个向量 如果它的参数是一个向量,它返回的是一个向量 如果它的参数是一个标量,它返回的是指定大小的单位矩阵 > diag(2) [,1] ...

  5. 3106: [cqoi2013]棋盘游戏

    3106: [cqoi2013]棋盘游戏 链接 分析: 极大极小搜索 + 记忆化. 代码 #include<bits/stdc++.h> using namespace std; type ...

  6. 1394-Minimum Inversion Number

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  7. 5.hbase表新增数据同步之add_peer

    一.前提主从集群之间能互相通讯: 二.在cluster1上(源集群):  1.查看集群已开启的peers hbase(main):011:0> list_peers PEER_ID CLUSTE ...

  8. Datetime与Datetime2的区别

    Datetime:        时间格式,对应于数据库中的DateTime类型,对应于.NET里面的System. DateTime类型.DateTime支持日期从1753年1月1日到9999年12 ...

  9. 位运算 & 网络序字节序

    一.初识位运算 位运算,见词明意,二进制运算,通常需要将运算数转换为二进制再进行处理,如果是在程序语言中则无需自己进行进制转换,基本的位操作符有如下几种:与(&).或(|).异或(^).取反( ...

  10. 构建Http服务器

    可以通过多种途径来构建服务器用以响应客户端请求(~不提供实现源码,网上有相应资源~) (1)使用ServerSocket构建服务器 (2)使用Servlet构建服务器 (3)使用HttpServer构 ...