HDU 2586 How far away ?(经典)(RMQ + 在线ST+ Tarjan离线) 【LCA】
<题目链接>
题目大意:
给你一棵带有边权的树,然后进行q次查询,每次查询输出指定两个节点之间的距离。
解题分析:
本题有多重解决方法,首先,可用最短路轻易求解。若只用LCA解决本题,也有三种常用的做法,具体方法如下:
LCA转RMQ解法:
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
;
int dis[M],dep[M],first[M],pos[M];
];
int cnt;
struct Edge{
int to,w;
};
vector<Edge>G[M];
int Min(int a,int b){ //得到深度更小的节点的序号,即更上层的节点
return dep[a]<dep[b]?a:b;
}
void RMQ_init(int n){ //预处理ST表,得到从[i,i+2^j-1]这个区间深度最小的节点的序号,注意,区间的下标代表遍历到的顺序
;i<=n;i++)
st[i][]=i;
;(<<j)<=n;j++)
;i+(<<j)-<=n;i++)
st[i][j]=Min(st[i][j-],st[i+(<<(j-))][j-]);
}
int RMQ(int l,int r){ //得到指定区间内深度最小的节点的编号,注意这里的l和r指的是按dfs顺序遍历的时间序号
))/log(2.0);
<<k)+][k]);
}
int get_LCA(int a,int b){ //在两点遍历顺序的区间内选择深度最小的节点的下标
return first[a]<first[b]?pos[RMQ(first[a],first[b])]:pos[RMQ(first[b],first[a])];
}
void dfs(int u,int fa,int deep){
dep[cnt]=deep,pos[cnt]=u,first[u]=cnt++; //表示cnt时间遍历到的节点的深度,和cnt时间遍历到的节点的序号,和第一次遍历到u节点的时间
;i<G[u].size();i++){
int v=G[u][i].to;
if(v==fa)continue;
dis[v]=dis[u]+G[u][i].w; //更新子节点距离
dfs(v,u,deep+);
pos[cnt]=u; //在dfs搜索完u的所有子节点后,回溯到u
dep[cnt++]=deep; //u的深度仍然为当前的深度
}
}
int main(){
int T,n,m;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
cnt=;
;i<M;i++)
G[i].clear();
;i<n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
G[a].push_back(Edge{b,c}); //建无向边
G[b].push_back(Edge{a,c});
}
dfs(,-,);
RMQ_init(*n-);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
printf(*dis[get_LCA(a,b)]);
}
}
;
}
在线ST解法可以看这篇博客 >>>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
;
struct node{
int to,w,next;
}e[maxn*];
],n,cnt,head[maxn];
void add(int u,int v,int w){
e[cnt].to=v,e[cnt].w=w;
e[cnt].next=head[u],head[u]=cnt++;
}
void dfs(int u,int pre,int t){
dep[u]=t;//深度
f[u]=pre;//父节点
;i=e[i].next){
int v=e[i].to;
if(v!=pre){
dis[v]=dis[u]+e[i].w;//距离跟的距离
dfs(v,u,t+);
}
}
}
void init()
{
//p[i][j]表示i结点的第2^j祖先
int i,j;
;(<<j)<=n;j++)
;i<=n;i++)
p[i][j]=-;
;i<=n;i++)p[i][]=f[i];
;(<<j)<=n;j++)
;i<=n;i++)
]!=-)
p[i][j]=p[p[i][j-]][j-];//i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先
}
int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y); //令x为深度更深的节点
int d=dep[x]-dep[y];
;(d>>i)!=;i++)
)x=p[x][i]; //以上的操作是处理较深的节点,使两节点深度一致
if(x==y)return x; //如果深度一致时,两节点相同,那么直接返回即可
;i>=;i--)
if(p[x][i]!=p[y][i]){ //跳2^i步不一样,就跳,否则不跳
x=p[x][i];
y=p[y][i];
}
]; //上述操作做完,两点的LCA都在上一层,所以再走一步即可
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int m,i,a,b,c,ans;
scanf("%d%d",&n,&m);
memset(head,-,sizeof(head));
cnt=;
;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
dis[]=;
dfs(,-,);//找到各点的深度和各点的父节点以及距离根的距离
init(); //初始各个点的2^j祖先是谁
;i<m;i++){
scanf("%d%d",&a,&b);
ans=dis[a]+dis[b]-*dis[LCA(a,b)];
printf("%d\n",ans);
}
}
;
}
离线Tarjan算法可以看这篇博客 >>> ,还有这篇 >>>
#include<iostream>
#include<cstdio>
#include<cstring>
#define Maxn 40010
#define Maxm 210
using namespace std;
struct edge{
int fr,to,w,lca,next;
}p[Maxn<<],ask[Maxm<<];
int head[Maxn],ah[Maxn];
int tot,tot1;
void addedge(int a,int b,int c){
p[tot].to=b;
p[tot].w=c;
p[tot].next=head[a];
head[a]=tot++;
}
void addedge1(int a,int b){
ask[tot1].fr=a;
ask[tot1].to=b;
ask[tot1].next=ah[a];
ah[a]=tot1++;
}
int fa[Maxn];
int findset(int x){ //寻找根节点
return fa[x]==x?x:(fa[x]=findset(fa[x]));
}
void unionset(int a,int b){ //将a、b的根节点链接
fa[findset(a)]=findset(b);
}
int vis[Maxn];
int anc[Maxn];
int dist[Maxn];
void LCA(int u,int fa){
;i=p[i].next){
int v=p[i].to;
if(fa!=v){
dist[v]=dist[u]+p[i].w;
LCA(v,u);
unionset(u,v); //将子树合并到父亲
anc[findset(u)]=u; //维护新集合指向父亲
}
}
vis[u]=; //设置已访问
;i=ask[i].next){ //处理与u关联的边
int v=ask[i].to;
if(vis[v]) //若v已访问,则说明u,v的lca是v所在集合的指向
ask[i].lca=ask[i^].lca=anc[findset(v)];
}
}
void init(int n){
tot=tot1=;
memset(head,-,sizeof head);
memset(ah,-,sizeof ah);
memset(vis,,sizeof vis);
;i<=n;i++) fa[i]=i;
}
int main()
{
int t,n,m,a,b,c;
cin>>t;
while(t--){
cin>>n>>m;
init(n);
;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
;i<=m;i++){ //把全部的query也建一颗无向树,进行离线处理
scanf("%d%d",&a,&b);
addedge1(a,b);
addedge1(b,a);
}
dist[]=;
LCA(,-);
;i<tot1;i+=)
printf(*dist[ask[i].lca]);
}
;
}
2018-10-20
HDU 2586 How far away ?(经典)(RMQ + 在线ST+ Tarjan离线) 【LCA】的更多相关文章
- HDU 4757 Tree(可持久化Trie+Tarjan离线LCA)
Tree Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others) Total Su ...
- hdu 2586(LCA在线ST)
How far away ? Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total Submission(s): A ...
- HDU 2586 How far away ?(LCA模板 近期公共祖先啊)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the vi ...
- hdu2586(lca模板 / tarjan离线 + RMQ在线)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意: 给出一棵 n 个节点的带边权的树, 有 m 个形如 x y 的询问, 要求输出所有 x, ...
- HDU 2586 (LCA模板题)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2586 题目大意:在一个无向树上,求一条链权和. 解题思路: 0 | 1 / \ 2 3 ...
- HDU 2586 LCA
题目大意: 多点形成一棵树,树上边有权值,给出一堆询问,求出每个询问中两个点的距离 这里求两个点的距离可以直接理解为求出两个点到根节点的权值之和,再减去2倍的最近公共祖先到根节点的距离 这是自己第一道 ...
- 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
hdu 2586 How far away ?倍增LCA 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2586 思路: 针对询问次数多的时候,采取倍增 ...
- LCA(最近公共祖先)--tarjan离线算法 hdu 2586
HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
随机推荐
- oracle 11g完全彻底的卸载
1.关闭oracle所有的服务.可以在windows的服务管理器中关闭: 2.打开注册表:regedit 打开路径: <找注册表 :开始->运行->regedit> HKEY ...
- Oracle11g 体系结构
一:Oracle11g 体系结构 二:逻辑储存结构 二.1:数据块(data blocks) ----通过 v$parameter数据字典来查询oracle标准数据块的大小. SYS@orcl> ...
- Confluence 6 禁用管理员联系表单
如果你希望禁用这个功能,不允许用户通过发送电子邮件的方式联系站点管理员.你可以禁用这个页面中有关输入用户信息发送电子邮件的部分.你只能禁用用户电子邮件输入表单,如果你按照上面描述的步骤在 'Custo ...
- 高性能JavaScript读后感
这本书让lz对js性能优化有了更深刻的理解,现在因为我们通常用第三方构建工具webpack.gulp等诸如此类,之前总是听说什么dom操作影响性能呢,对这个概念总是有点模糊,但看完这本书之后后,相对而 ...
- py4测试题
1.8<<2等于? 32 2.通过内置函数计算5除以2的余数 print(divmod(5,2))------>1 3.s=[1,"h",2,"e&qu ...
- 《剑指offer》 链表中倒数第k个节点
本题来自<剑指offer> 链表中倒数第k个节点 题目: 输入一个链表,输出该链表中倒数第k个结点. 思路: 倒数第k个节点,而且只能访问一遍链表,定义两个节点,两者之间相差k个距离,遍历 ...
- Eclipse搭建.C#和..NET Core环境
1.在上一篇博客中我介绍了如何使用Eclipse搭建C++.C开发环境,顺带把搭建 .NET Core 和C#也做个介绍.配置任何环境关键是找到要开发语言的编辑器和SDK.eclipse是java开发 ...
- SSM + Android 网络文件上传下载
SSM + Android 网络交互的那些事 2016年12月14日 17:58:36 ssm做为后台与android交互,相信只要是了解过的人都知道一些基本的数据交互,向json,对象,map的交互 ...
- SSM文件下载
SSM框架文件下载比文件上传稍微麻烦一点,但这次还是写成最简朴的形式,哈哈~如下 参考:http://blog.csdn.net/lcx556224523/article/details/702076 ...
- WCF寄宿IIS
1.创建一个简单的wcf项目 创建完成后直接运行,结果 然后进行发布 在IIS上新建一个网站,直接进行发布即可 遇到的问题 请求与通配符 mime 映射相匹配.请求映射到静态文件处理程序. 需要注意的 ...