[hdu 2586]lca模板题(在线+离线两种版本)
题目链接: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模板题(在线+离线两种版本)的更多相关文章
- HDU 2586 (LCA模板题)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2586 题目大意:在一个无向树上,求一条链权和. 解题思路: 0 | 1 / \ 2 3 ...
- hdu - 2586 (LCA板子题)
传送门 (这次的英文题面要比上一个容易看多了) (英语蒟蒻的卑微) 又是一个很裸的LCA题 (显然,这次不太容易打暴力咧) (但听说还是有大佬用dfs直接a掉了) 正好 趁这个机会复习一下LCA 这里 ...
- 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 ...
- POJ 1470 Closest Common Ancestors (模板题)(Tarjan离线)【LCA】
<题目链接> 题目大意:给你一棵树,然后进行q次询问,然后要你统计这q次询问中指定的两个节点最近公共祖先出现的次数. 解题分析:LCA模板题,下面用的是离线Tarjan来解决.并且为了代码 ...
- 【转载】pygame安装与两种版本的Python兼容问题
在开始学习游戏编程之前,我们先来安装下pygame和python3.2.5 参考园友: http://www.cnblogs.com/hongten/p/hongten_pygame_install. ...
- HDU - 2586 How far away ?(LCA模板题)
HDU - 2586 How far away ? Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & ...
- HDU 2586——How far away ?——————【LCA模板题】
How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- HDU2586 How far away ?(LCA模板题)
题目链接:传送门 题意: 给定一棵树,求两个点之间的距离. 分析: LCA 的模板题目 ans = dis[u]+dis[v] - 2*dis[lca(u,v)]; 在线算法:详细解说 传送门 代码例 ...
- HDU 2586 LCA
题目大意: 多点形成一棵树,树上边有权值,给出一堆询问,求出每个询问中两个点的距离 这里求两个点的距离可以直接理解为求出两个点到根节点的权值之和,再减去2倍的最近公共祖先到根节点的距离 这是自己第一道 ...
随机推荐
- python七类之列表元组
列表 一.关键字: list lst = [ , , , , , , ,] lst = [1,2,3,4] 二.方法: 1.增加: . append( ) #追加,添加元素进列表最后 ls ...
- 新手学习ARM,对片内ram、SDRAM、NOR FLASH和NAND FLASH启动这几个概念的理解
片内的ram用来存储启动代码,在2440初始化sdram之前,代码就在片内ram中运行.片内ram装载的是norflash中的内容,即u-boot. uboot放在norflash里,nandflas ...
- [ACM] POJ 2409 Let it Bead (Polya计数)
参考:https://blog.csdn.net/sr_19930829/article/details/38108871 #include <iostream> #include < ...
- redhat6.4 安装Oracle11gR2 遇到的问题
http://blog.sina.com.cn/s/blog_53a5865c0102e2u6.html 1.使用的时候出现一个错误: /lib/ld-linux.so.2: bad ELF in ...
- 面试官常问的10个Linux问题
1.如何暂停一个正在运行的进程,把其放在后台(不运行)? 为了停止正在运行的进程,让其再后台运行,我们可以使用组合键Ctrl+Z. 2.什么是安装Linux所需的最小分区数量,以及如何查看系统启动信息 ...
- 预装win8的笔记本如何重装win7
测试电脑联想T440. 开机按F1,然后Enter,进入Bios设置. 先关闭Secure Boot,然后设置为Legacy Boot. 之后才能设置U盘为第一启动盘. 进入老毛桃的PE系统,使用Di ...
- java集合浅谈(一)
一.类库结构图概览 容器对象仅能持有对象引用(对象的指针),而不是Copy对象信息,从网上搜得几张Java中集合类库的结构图,如下所示: 二.解说Collection 2.1 Collection ( ...
- linux开发基本库
1.ZeroMQ zmq是一个消息队列.可以在进程内.进程间.TCP.多播中,以消息为单位传输数据,而不是socket的字节流.官方主页上有下载.使用.文档,蛮全的. 常用模式有:Request-Re ...
- Qt Creater 制作汽车仪表盘
最近项目用到了模拟仪表,网上下载大神编写的按个仪表Meter没有成功 转战 QWt 编译后,在creater中仍然无法使用,只可以在代码中使用 百度说是我编译的版本不对 扔到 开始做自己的 这个用到了 ...
- 贝叶斯网(1)尝试用Netica搭建简单的贝叶斯网并使用贝叶斯公式解释各个bar的结果
近来对贝叶斯网十分感兴趣,按照博客<读懂概率图模型:你需要从基本概念和参数估计开始>给出的第一个例子,试着搭建了一个student网. (1)点击绿F,对条件概率表予以输入(包括两个祖先节 ...