题意还是很有病的,说了半天后边的方向都没用的,意思就是跟样例一样求两点间的距离,裸的LCA

两个点x,y的距离=dis[x]+dis[y]-2*dis[LCA(x,y)];

三个点x,y,z的距离=dis[x]+dis[y]+dis[z]-dis(lca(x,y))-dis(lca(y,z))-dis(lca(x,z));

倍增的思想是感觉跟RMQ很像,就是首先建数存路径与各节点深度,首先来说最暴力的方法就是将两点中深度大的点跳到与深度小的点一样深度,然后两个点一起往上跳一层一层的跳,最后总能跳到同一个位置。like this,但是显然复杂度大的不谈。

if(dep[u]<dep[v]) swap(u,v);
int x=(dep[u]-dep[v]);
while(x--)u=f[u];
while(u!=v)
{u=f[u];v=f[v];
}

所以说倍增的方法就是通过一个二维的f[u][i]数组来表示u节点往上跳2^i方个节点。

那么比如说一个深度为10的u点和一个深度为5的v点,先将u点跳到v点的深度,就需要u先往上跳5个,转化成二进制不就是101.

那么u先往上跳一格f变成 f[u][0],然后再想上跳4格就是2的2次方 f[f[u][0]] [2],然后就跳到一个层了。

然后两个一起向上跳也是一样的,不再是一个一个的向上跳,而是尽量以2的n次方向上跳,也就是说深度差为int范围内只需跳不超过32次。所以就大大简化了复杂度,并且是在线 的。

那么怎么求f数组呢,在理解就是f[u][i]当i>0时,f[u][i]=f[f[u][i-1]] [i-1]类似于折半的感觉就能把f数组提前处理出来。

代码

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define inff 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define PI 3.14159265358979323846
#define me(a,b) memset(a,b,sizeof(a))
#define min4(a,b,c,d) min(min(a,b),min(c,d))
#define min3(x,y,z) min(min(x,y),min(y,z))
const int dir[4][2]= {0,-1,-1,0,0,1,1,0};
typedef long long ll;
const ll inFF=9223372036854775807;
typedef unsigned long long ull;
using namespace std;
const int maxn=4e4+5;
int f[maxn][20],d[maxn],head[maxn],dis[maxn];//d表示深度,dis表示到root距离,f表示父节点关系
int n,m,sign;
struct node
{int to,p,val;
}edge[maxn<<1];
void init()
{sign=0;for(int i=1;i<=n;i++)head[i]=-1;
}
void add(int u,int v,int val)
{edge[sign]=node{v,head[u],val};head[u]=sign++;
}
void dfs(int u)
{for(int i=head[u];~i;i=edge[i].p){int v=edge[i].to;if(v==f[u][0]) continue;d[v]=d[u]+1;dis[v]=edge[i].val+dis[u];f[v][0]=u;//f[v][0]就是v的father就是udfs(v);}
}
void getf() //得到数组也是上述的那个理解
{for(int j=1;(1<<j)<=n;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int a,int b)
{if(d[a]<d[b]) swap(a,b);//把a变成那个深度大的int x=d[a]-d[b];//距离差for(int i=0;(1<<i)<=x;i++)if((1<<i)&x) a=f[a][i];//把a跳到跟b一样的深度if(a!=b){for(int i=(int)log2(n);i>=0;i--)//这个要从大的步子往小步子跳if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];a=f[a][0];}return a;//返回lca
}
int main()
{char ch;int x,y,z,k;while(cin>>n>>m){init();for(int i=1;i<=m;i++) scanf("%d %d %d %c",&x,&y,&z,&ch),add(x,y,z),add(y,x,z);f[1][0]=1,dis[1]=0,d[1]=1;dfs(1);getf();cin>>k;for(int i=1;i<=k;i++){scanf("%d %d",&x,&y);cout<<dis[x]+dis[y]-2*dis[lca(x,y)]<<endl;}}return 0;
}

POJ - 1986 Distance Queries 倍增求LCA相关推荐

  1. poj 1986 Distance Queries LCA

    题目链接:http://poj.org/problem?id=1986 Farmer John's cows refused to run in his marathon since he chose ...

  2. POJ 1986 Distance Queries(LCA)

    [题目链接] http://poj.org/problem?id=1986 [题目大意] 给出一棵树,问任意两点间距离. [题解] u,v之间距离为dis[u]+dis[v]-2*dis[LCA(u, ...

  3. poj 1986 Distance Queries

    LCA 题意:LCA模板题,输入n和m,表示n个点m条边,下面m行是边的信息,两端点和权,后面的那个字母无视掉,没用的.接着k,下面k个询问lca,输出即可 有人说要考虑不连通的情况,我没考虑AC了, ...

  4. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  5. CodeVS3287[NOIP2013] 货车运输【Kruskal+倍增求LCA】

    题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过 ...

  6. 《信息学奥赛一本通 提高篇》 第四部分 数据结构 第4章 倍增求LCA

    例题1 点的距离 信息学奥赛一本通(C++版)在线评测系统 例题2 暗的连锁(Poj3417) 信息学奥赛一本通(C++版)在线评测系统 LOj10131 暗的连锁_juruo_xlh-CSDN博客 ...

  7. POJ 1986:Distance Queries(倍增求LCA)

    http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点 ...

  8. 树上倍增求LCA详解

    LCA(least common ancestors)最近公共祖先 指的就是对于一棵有根树,若结点z既是x的祖先,也是y的祖先(不要告诉我你不知道什么是祖先),那么z就是结点x和y的最近公共祖先. 定 ...

  9. 【代码源 Div1 - 105】#451. Dis(倍增求LCA)

    problem solution 给出 n 个点的一棵树,每个点有各自的点权,m 次询问两个点简单路径所构成点集的异或和. 直接在树上求LCA,把每个点权放进去预处理一下即可. #include< ...

最新文章

  1. Charles是Mac的Fiddler抓包工具
  2. SQL基础【十三、通配符】
  3. 文件操作(解密加密)
  4. 核心动画--基本动画
  5. 【测试】测试用例8大法
  6. GCC4.8对new和delete的参数匹配新要求
  7. requestAnimationFrame 优化Web动画
  8. 简单实现系统托盘 - 回复 闪 的问题
  9. spring boot启动加载外部配置文件
  10. 简单理解:类目、SPU、SKU
  11. Day6789:Keep Calm N Carry On
  12. u盘为什么要安全弹出?丢失的数据怎么恢复?
  13. C语言:for循环(for循环,while 循环:计算1加到100的值)
  14. SQL server 期末复习
  15. 服务器硬盘上面的12gb和6gb的区别,4GB和6GB有什么区别?看完千万别买错,已有多人后悔!...
  16. 如何检查后台服务(Android的Service类)是否正在运行?
  17. linux usb总线接4g,Linux下4G LTE连接
  18. 如何将excel表格导入word_word办公技巧:如何让Excel与Word文档数据同步
  19. 没有广泛爱好的人,就不是热爱生活…
  20. gpio驱动重构版,未优化,附上测试demo

热门文章

  1. Android 编译源码 注意事项
  2. Android studio 文件包名连在一起的处理方法
  3. Buttomsheetdialog的简单实用
  4. ImageView 常用属性的分析
  5. BZOJ 1003[ZJOI2006]物流运输(SPFA+DP)
  6. [转]slf4j + log4j原理实现及源码分析
  7. MongoDB(一):安装
  8. JSON http://www.cnblogs.com/haippy/archive/2012/05/20/2509329.html
  9. openoj的一个小比赛(F题解题报告)poj3978(dp+素数筛选)
  10. awk linux 获取端口号_Linux提权后获取敏感信息命令