http://acm.hdu.edu.cn/showproblem.php?pid=2586

给出一颗树和边权,询问两点距离。

考虑tarjan离线做法,做法很巧妙,当前进行到u,对他的儿子v,当v子树tarjan完成之后把v合并到u上。当遍历完所有v之后,对与u有关的询问进行查找,若第二个询问点v被访问过,那么lca(u,v)就是v目前被合并到的根上。还有记录d[u]表示根到u的距离。

  最后答案就是d[u]+d[v]-2*d[lca(u,v)]。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<stack>
#include<deque>
#include<bitset>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<cstdlib>
#include<ctype.h>
#include<ctime>
#include<functional>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define debug puts("debug")
#define mid ((L+R)>>1)
#define lc (id<<1)
#define rc (id<<1|1)
const int maxn=;
const int maxm=;
const double PI=acos(-1.0);
const double eps=1e-;
const LL mod=1e9+;
LL gcd(LL a,LL b){return b==?a:gcd(b,a%b);}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL qpow(LL a,LL b,LL c){LL r=; for(;b;b>>=,a=a*a%c)if(b&)r=r*a%c;return r;}
template<class T>
void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
struct Edge{int u,v,w,next;}; vector<pii>g[maxn],q[maxn];
int d[maxn],f[maxn],qu[],qv[],ans[];
bool vis[maxn];
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
void tarjan(int u){
vis[u]=;
for(pii e:g[u]){
int v=e.fi,w=e.se;
if(!vis[v]){
d[v]=d[u]+w;
tarjan(v);
f[v]=u;
}
}
for(pii e:q[u]){
int v=e.fi,id=e.se;
if(vis[v]){
ans[id]=getf(v);
}
}
}
int main(){
int t,n,m,i,j,u,v,w;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(i=;i<=n;++i){
g[i].clear();
q[i].clear();
f[i]=i;
vis[i]=;
}
for(i=;i<n;++i){
scanf("%d%d%d",&u,&v,&w);
g[u].pb(mp(v,w));
g[v].pb(mp(u,w));
}
for(i=;i<=m;++i){
scanf("%d%d",qu+i,qv+i);
q[qu[i]].pb(mp(qv[i],i));
q[qv[i]].pb(mp(qu[i],i));
}
tarjan();
for(i=;i<=m;++i){
printf("%d\n",d[qu[i]]+d[qv[i]]-*d[ans[i]]);
}
}
return ;
}

接着用ST在线做法又做了一遍。如果题目强制在线的话,tarjan做法就gg了,我们提前不知道询问便无法离线做了。

ST做法是每次访问到一个节点就记录下当前的节点值和深度,当查询lca(u,v)的时候,先找到u和v第一次访问到的位置L和R(L<=R),

然后在[L,R]中找到一个深度最小的点,他对应的节点值w=lca(u,v)。RMQ问题,使用ST处理O(nlog(n))。询问就可以O(1)啦。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<stack>
#include<deque>
#include<bitset>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<cstdlib>
#include<ctype.h>
#include<ctime>
#include<functional>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define debug puts("debug")
#define mid ((L+R)>>1)
#define lc (id<<1)
#define rc (id<<1|1)
const int maxn=;
const int maxm=;
const double PI=acos(-1.0);
const double eps=1e-;
const LL mod=1e9+;
LL gcd(LL a,LL b){return b==?a:gcd(b,a%b);}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL qpow(LL a,LL b,LL c){LL r=; for(;b;b>>=,a=a*a%c)if(b&)r=r*a%c;return r;}
template<class T>
void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
struct Edge{int u,v,w,next;}; vector<pii>g[maxn];
vector<int>dep,idx;
int f[maxn*][],d[maxn],p[maxn];
void dfs(int u,int o,int fa){
p[u]=idx.size();
idx.pb(u),dep.pb(o);
for(pii e:g[u]){
int v=e.fi,w=e.se;
if(v!=fa){
d[v]=d[u]+w;
dfs(v,o+,u);
idx.pb(u),dep.pb(o);
}
}
}
void ST(int n){
for(int i=;i<n;++i)f[i][]=i;
for(int j=;(<<j)<=n;j++){
for(int i=;(i+(<<j)-)<n;i++){
f[i][j]=dep[f[i][j-]]<dep[f[i+(<<(j-))][j-]]?f[i][j-]:f[i+(<<(j-))][j-];
}
}
}
int ask(int L,int R){
int k=;
while((<<(+k))<=R-L+)k++;
return dep[f[L][k]]<dep[f[R-(<<k)+][k]]?idx[f[L][k]]:idx[f[R-(<<k)+][k]];
}
int main(){
int t,n,m,i,j,u,v,w;
scanf("%d",&t);
while(t--){
idx.clear();
dep.clear();
scanf("%d%d",&n,&m);
for(i=;i<=n;++i){
g[i].clear();
}
for(i=;i<n;++i){
scanf("%d%d%d",&u,&v,&w);
g[u].pb(mp(v,w));
g[v].pb(mp(u,w));
}
dfs(,,);
ST(idx.size());
// prt(idx);
// prt(dep);
while(m--){
scanf("%d%d",&u,&v);
int L=p[u],R=p[v];
if(L>R)swap(L,R);
printf("%d\n",d[u]+d[v]-*d[ask(L,R)]);
}
}
return ;
}
/*
5
7 7
1 2 1
1 3 1
2 4 1
2 5 1
5 6 1
5 7 1
*/

  综上两种方法而言,我感觉思想都是类似是,就是u-->v这条路一定经过他们的共同祖先,这中间过程中经过若干个点,我们要想办法找到深度最小的那个点,显然他只会被经过一次,就是LCA。

HDU-2586-裸LCA入门-tarjan离线的更多相关文章

  1. hdu 2586(裸LCA)

    传送门 题意: 某村庄有n个小屋,n-1条道路连接着n个小屋(无环),求村庄A到村庄B的距离,要求是经过任一村庄不超过一次. 题解: 求出 lca = LCA(u,v) , 然后答案便是dist[u] ...

  2. hdu2586(lca模板 / tarjan离线 + RMQ在线)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意: 给出一棵 n 个节点的带边权的树, 有 m 个形如 x y 的询问, 要求输出所有 x, ...

  3. 洛谷 P3379 【模板】最近公共祖先(LCA)Tarjan离线

    题目链接:LCA tarjan离线 这道题目WA无数发,最后还是参考了大神的blog 谁会想到因为一个输入外挂WA呢 大概是我的挂是假挂吧...orz(其实加上外挂,速度提升很多) 用链式前向星保存边 ...

  4. POJ 1330 Nearest Common Ancestors 【最近公共祖先LCA算法+Tarjan离线算法】

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20715   Accept ...

  5. HDU 2586.How far away ?-离线LCA(Tarjan)

    2586.How far away ? 这个题以前写过在线LCA(ST)的,HDU2586.How far away ?-在线LCA(ST) 现在贴一个离线Tarjan版的 代码: //A-HDU25 ...

  6. HDU 2586 How far away ? 离线lca模板题

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. LCA之tarjan离线

    显然81篇题解是有点多了,不让我提交. 更为不好的是没有一篇详细的\(tarjan\)(不过我也不会写详细的). 不过\(tarjan\)并没有我们想象的那样难理解,时间也并不爆炸(巧妙的跳过难写二字 ...

  8. How far away ? HDU - 2586 【LCA】【RMQ】【java】

    题目大意:求树上任意两点距离. 思路: dis[i]表示i到根的距离(手动选根),则u.v的距离=dis[u]+dis[v]-2*dis[lca(u,v)]. lca:u~v的dfs序列区间里,深度最 ...

  9. POJ 1986 Distance Queries 【输入YY && LCA(Tarjan离线)】

    任意门:http://poj.org/problem?id=1986 Distance Queries Time Limit: 2000MS   Memory Limit: 30000K Total ...

随机推荐

  1. (转) Dissecting Reinforcement Learning-Part.2

    Dissecting Reinforcement Learning-Part.2 Jan 15, 2017 • Massimiliano Patacchiola 原文链接:https://mpatac ...

  2. (转载)C# GDI+ 画简单的图形:直线、矩形、扇形等

    GDI+是一种绘图装置接口, 当拖动窗体是,窗体发生移动,window默认为从窗体移动到另一个地方,先发生擦除后再重新画一个窗体: 而我们自己动手画的图(如下面的线),不会重新画:在属性中,Paint ...

  3. Images之Dockerfiles

    Best practices for writing Dockerfiles This document covers recommended best practices and methods f ...

  4. 如何判断一个单向链表是否为回文链表(Palindrome Linked List)

    题目:给定一个单向链表,判断它是不是回文链表(即从前往后读和从后往前读是一样的).原题见下图,还要求了O(n)的时间复杂度O(1)的空间复杂度. 我的思考: 1,一看到这个题目,大脑马上想到的解决方案 ...

  5. HDU 4825 Xor Sum(01字典树入门题)

    http://acm.hdu.edu.cn/showproblem.php?pid=4825 题意: 给出一些数,然后给出多个询问,每个询问要从之前给出的数中选择异或起来后值最大的数. 思路:将给出的 ...

  6. Python cmd中输入'pip' 不是内部或外部命令,也不是可运行的程序或批处理文件。

    配置一下环境变量,找到 添加一下Scripts文件夹的路径,如:这是我的路径C:\Users\ck\AppData\Local\Programs\Python\Python36 就是你python的安 ...

  7. R----ggplot2包介绍学习--转载

    https://www.cnblogs.com/nxld/p/6059603.html 分析数据要做的第一件事情,就是观察它.对于每个变量,哪些值是最常见的?值域是大是小?是否有异常观测? ggplo ...

  8. git项目,VSCode显示不同颜色块的含义

    一. 概念 代码里的左侧颜色标识: 红色,未加入版本控制; (刚clone到本地) 绿色,已经加入版本控制暂未提交; (新增部分) 蓝色,加入版本控制,已提交,有改动: (修改部分) 白色,加入版本控 ...

  9. 软件测试中Bug的生命周期以及Bug的严重等级

    软件测试中Bug的生命周期以及Bug的严重等级 我猜你们都会,但能说专业且全面不? 1.首先当测试人员接到一个项目或产品准备测试的时候,测试人员会根据测试用例一步步的来执行用例进行简单的功能测试.当测 ...

  10. [HTTP]_[C/C++]_[解析URL的转义字符百分比字符串]

    场景: 1.有时候获取一个超链接时,或者一个图片src时,里面的地址带有%XX,这样如果当成文件路径处理会不识别.所以要把转义字符解码. 2.它其实就是ASCII码的十六进制表示. 以下是stacko ...