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/ ...
随机推荐
- 【VBA】数组定义时,括号内的数值n为最大下标,其长度为n+1
定义数组 dim arr(9) as integer注意这是数组的长度为10,而9指的是最大下标值. 所以在redim和赋值的时候要特别小心,防止错位.
- nginx官方模块之http_sub_status_module
作用 显示nginx的连接状态,nginx客户端状态 配置语法 配置
- linux cp命令使用
功能: 复制文件或目录说明: cp指令用于复制文件或目录,如同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前面指定的所有文件或目录复制到此目录中.若同时指定多个文件或目录, ...
- java 接口实现的概念整理
1.在java语言中接口由类实现,以便使用接口中的方法,重写接口中的方法,实现接口的类必须重写接口中的所有类,由于接口中的方法一定是 public abstract方法,所以类重写接口中的方法不仅要去 ...
- java web----URL
简单使用 import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; im ...
- poj2728 生成树01分数规划 (二分答案)
给定整数序列a,b,求出下式的最大值 sum{ai*xi}/sum{bi*xi},xi=0|1 通俗来说,就是选出一些整数对(ai,bi),使得选出的a之和与选出的b之和商最大化 二分答案L,即选出的 ...
- JS实现继承的几种方式(转)
转自:幻天芒的博客 前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一.那么如何在JS中实现继承呢?让我们拭目以待. JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如 ...
- servlet获取多个同名参数
String[] item = request.getParameterValues("参数名");
- Mom and Dad
Mom Poodwaddle Life clock Dad Poodwaddlw Life clock Happiness is the meaning and the purpose of lif ...
- GAN-生成手写数字-Keras
from keras.models import Sequential from keras.layers import Dense from keras.layers import Reshape ...