题目链接: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. C语言实例解析精粹学习笔记——32

    实例32: 编制一个包含姓名.地址.邮编和电话的通讯录输入和输出函数. 思路解析: 1.用结构体来完成姓名.地址.邮编和电话的组合. 2.结构体指针的使用. 3.malloc的使用 4.scanf函数 ...

  2. HDOJ 1176 免费馅饼(完全背包)

    参考:https://blog.csdn.net/hhu1506010220/article/details/52369785 https://blog.csdn.net/enjoying_scien ...

  3. Ubuntu无法安装vim怎么办?(Ubuntu 出现apt-get: Package has no installation candidate问题)

    apt-get install vim 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 有一些软件包无法被安装.如果您用的是不稳定(unstable)发行版, ...

  4. struts2官方 中文教程 系列十一:使用XML进行表单验证

    在本教程中,我们将讨论如何使用Struts 2的XML验证方法来验证表单字段中用户的输入.在前面的教程中,我们讨论了在Action类中使用validate方法验证用户的输入.使用单独的XML验证文件让 ...

  5. Question | 关于Android安全的一二事

    本文来自网易云社区 "Question"为网易云易盾的问答栏目,将会解答和呈现安全领域大家常见的问题和困惑.如果你有什么疑惑,也欢迎通过邮件(zhangyong02@corp.ne ...

  6. C++重载赋值操作符

    1.C++中重载赋值操作函数应该返回什么? 类重载赋值操作符一般都是作为成员函数而存在的,那函数应该返回什么类型呢?参考内置类型的赋值操作,例如 int x,y,z; x=y=z=15; 赋值行为相当 ...

  7. 「暑期训练」「Brute Force」 Far Relative’s Problem (CFR343D2B)

    题意 之后补 分析 我哭了,强行增加自己的思考复杂度...明明一道尬写的题- -(往区间贪心方向想了 其实完全没必要,注意到只有366天,直接穷举判断即可. 代码 #include <bits/ ...

  8. Vue学习(二):class与style绑定

    <!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml&q ...

  9. 多图片上传(base64方式传至后台)

    <!DOCTYPE html><html><head> <meta http-equiv="X-UA-Compatible" conten ...

  10. memcached的认识

    <?php /* memcached概念: Memcached是一个免费开源的,高性能的,具有分布式对象的缓存系统,它可以用来保存一些经常存取的对象或数据,保存的数据像一张巨大的HASH表,该表 ...