[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倍的最近公共祖先到根节点的距离 这是自己第一道 ...
随机推荐
- scrapy框架爬取笔趣阁完整版
继续上一篇,这一次的爬取了小说内容 pipelines.py import csv class ScrapytestPipeline(object): # 爬虫文件中提取数据的方法每yield一次it ...
- (数据科学学习手札36)tensorflow实现MLP
一.简介 我们在前面的数据科学学习手札34中也介绍过,作为最典型的神经网络,多层感知机(MLP)结构简单且规则,并且在隐层设计的足够完善时,可以拟合任意连续函数,而除了利用前面介绍的sklearn.n ...
- R语言学习笔记(四):apply,sapply,lapply,tapply,vapply以及mapply的用法
apply() apply(m,dimcode,f,fargs) m 是一个矩阵. dimcode是维度编号,取1则为对行应用函数,取2则为对列运用函数. f是函数 fargs是f的可选参数集 > ...
- C# 集合之Dictionary详解
开讲. 我们知道Dictionary的最大特点就是可以通过任意类型的key寻找值.而且是通过索引,速度极快. 该特点主要意义:数组能通过索引快速寻址,其他的集合基本都是以此为基础进行扩展而已. 但其索 ...
- python 推导式的用法
推导式看了不少,可每次都有新发现 例子1:返回满足条件为真,否则为假 try_list = [1, 2, 3, 4, 5] # 前2种一样, [a > 3 for a in b] [True i ...
- [Python 3.X]python练习笔记[2]-----用python实现七段数码管显示年月日
#SevenDigitsDrawV2.py import turtle import time def drawGap(i):#绘制数码管间隔 turtle.penup() turtle.fd(i) ...
- How to set pycharm configure for remoting development
配置pycharm远程连接,点击pycharm的tools,选择deployment选项,选择configuration. 2 点击左侧的加号按钮,新增一个连接,取个名字,根据个人配置选择协议,这里选 ...
- Windows下nginx作为静态资源服务器使用
一.Nginx下载与安装 1.nginx官方下载地址:http://nginx.org/ 2.下载完后将压缩包解压即可 3.nginx配置文件为根目录下conf\nginx.conf 二.Nginx常 ...
- Windows Server2003下安装IIS服务脑图
在练习过程中,勾选“ASP.NET”后开始安装时提示要插入安装光盘,但是我安装系统时是用镜像文件在虚拟机里安装的,所以根据提示界面的提示从文件中选择相应文件复制,如下图点击确定,选择iisapp.vb ...
- Unity动态换装之Spine换装
注:转载请注明转载,并附原链接 http://www.cnblogs.com/liaoguipeng/p/5867510.html 燕双飞情侣 一.动态换装原理 换装,无非就是对模型的网格,或者贴图进 ...