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/ ...
随机推荐
- flask 初学1
py 文件中 from flask import Flask,redirect,request,url_for,jsonifyfrom Flask_5.config import Config fro ...
- 新建maven项目错误处理
1.如果新建maven 项目确省maven dependencies,则在存在问题工程的.classpath末尾 加上 <classpathentry kind="con" ...
- redis-cluster集群搭建
Redis3.0版本之前,可以通过Redis Sentinel(哨兵)来实现高可用 ( HA ),从3.0版本之后,官方推出了Redis Cluster,它的主要用途是实现数据分片(Data Sha ...
- 剑指offer 二叉树中和为某一个值的路径
剑指offer 牛客网 二叉树中和为某一个值的路径 # -*- coding: utf-8 -*- """ Created on Tue Apr 9 15:53:58 2 ...
- js中json对象数组按对象属性排序(sort方法)---2(根据拼音排序汉字和排序英文)
本例主要实现 中文汉字按拼音排序的方法和英文按照首字母排序的方法. 要排序的数据: //要排序的数据 let data = [ {chinese: '蔡司', english: 'Chase'}, { ...
- 如何在地址栏(title标签里)和收藏夹里 加上网站的标志ICO、LOGO图片
第一步:首先你必须要制作一个看起来既清楚又容易辨识的.ico格式的小图片. 我们将图标的大小定义为16x16 像素.此外在制作图形文件的时候,你可能需要把色盘设定成只使用标准的 16 色 Window ...
- Python游戏编程(Pygame)
安装Pygame pip install pygame C:\Users> pip install pygame Collecting pygame Downloading https://fi ...
- MySQL基于ROW格式的数据恢复
大家都知道MySQL Binlog 有三种格式,分别是Statement.Row.Mixd.Statement记录了用户执行的原始SQL,而Row则是记录了行的修改情况,在MySQL 5.6以上的版本 ...
- Appium Demo
import unittestimport timefrom appium import webdriverfrom public import configimport os #类继承unittes ...
- netty 学习(1)
Netty使用:通过BootStrap来启动.而BootStrap主要分为两类:1.面向连接(TCP)的(ClientBootStrap和ServerBootStrap);2. 非面向连接(UDP)的 ...