倍增LCA

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int M = 200005;
struct Edge{
    int v, next;
} edge[M << 1];
int E; int head[M];
void add_edge(int s, int v){
    edge[E].next = head[s];
    edge[E].v = v;
    head[s] = E ++;
}
int fa[M][23];

int deep[M];
int vis[M];
int sum[M];

void bfs(){
    queue<int> q;
    q.push(1);
    memset(vis, 0, sizeof(vis));
    memset(sum, 0, sizeof(sum));
    fa[1][0] = 1;
    deep[1] = 0;
    vis[1] = 1;
    sum[1] = 1;
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int j = 1; j <= 20; j ++) {
            fa[u][j] = fa[fa[u][j-1]][j-1];
        }
        for(int i = head[u]; i != -1; i = edge[i].next){
            int v = edge[i].v;
            if(vis[v]) continue;
            sum[v] = sum[u] + 1;
            vis[v] = 1;

            fa[v][0] = u;
            deep[v] = deep[u] + 1;
            q.push(v);
        }
    }
}

int lca(int a, int b){
    if(deep[a] > deep[b]) swap(a, b);
    int ta = a; int tb = b;
    int da = deep[a]; int db = deep[b];
    for(int i = 0, dd = db - da; dd; dd >>= 1, i ++){
        if(dd&1)
            tb = fa[tb][i];
    }
    if(tb == ta) return tb;
    for(int i = 20; i >= 0; i --){
        if(fa[ta][i] == fa[tb][i]) continue;
        ta = fa[ta][i];
        tb = fa[tb][i];
    }
    return fa[ta][0];

}

int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    int a, b;
    memset(head, -1, sizeof(head));
    for(int i = 2; i <= n; i ++){
        scanf("%d", &a);
        add_edge(a, i);
        add_edge(i, a);
    }
    bfs();
    while(m --){
        scanf("%d%d", &a, &b);
        int lc = lca(a, b);
        if(deep[lc] == deep[a])
            printf("%d %d\n", sum[lc], sum[b] - sum[lc]);
        else if(deep[lc] == deep[b]){
            printf("%d %d\n", sum[a] - sum[lc], sum[lc]);
        }else {
            printf("%d %d\n", sum[a], sum[b] - sum[lc]);
        }
    }
    return 0;
}

  

时间: 2025-01-01 12:00:07

倍增LCA的相关文章

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些

【bzoj4242】水壶 BFS+最小生成树+倍增LCA

题目描述 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外. JOI君因为各种各样的事情,必须在各个建筑物之间往返.虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水.此外,原野上没有诸如自动售货机.饮水处之类的东西,因此IOI市的市民一般都携带水壶出

Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]

题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_dis[i],维护非子树节点中距离该点的最大值fa_dis[i]; 2.对于每个节点维护它最大的三个儿子节点的son_dis; 3.维护up[i][j]和down[i][j]数组,这个类似倍增lca里边的fa[i][j],up[i][j]代表的含义是从第j个点向上到它的第2^i个父节点这条链上的点除了该

Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB 总提交次数:196   AC次数:65   平均分:58.62 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 2013中国国家集训队第二次作业 问题描述 给定一棵N个节点的树,每个点有一个权值,有M个询问(a,b,c)若a 为1,回答b到c路径上的最小权值,若a为2,回答b到c路径上的最大权值,若a为3,回答b到c路径上的所有权值的

BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写

【BZOJ2815】【ZJOI2012】灾难 阿米巴和小强题 动态倍增LCA 灾难树

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44104163"); } 题意: 原题面请见JSShining博客 http://www.cnblogs.com/JS-Shining/archive/2013/01/12/2857429.html 题解: 我们构建一颗灾难树,使得一

BZOJ 2791 Poi2012 Rendezvous 倍增LCA

题目大意:给定一棵内向森林,多次给定两个点a和b,求点对(x,y)满足: 1.从a出发走x步和从b出发走y步会到达同一个点 2.在1的基础上如果有多解,那么要求max(x,y)最小 3.在1和2的基础上如果有多解,那么要求min(x,y)最小 4.如果在1.2.3的基础上仍有多解,那么要求x>=y 因此那个x>=y是用来省掉SPJ的,不是题目要求- - 容易发现: 如果a和b不在同一棵内向树上,显然无解,否则一定有解 定义根为从一个点出发能走到的第一个环上点,如果a和b的根相同,则到达LCA是

洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]

题目描述 Farmer John has installed a new system of  pipes to transport milk between the  stalls in his barn (), conveniently numbered . Each pipe connects a pair of stalls, and all stalls are connected to each-other via paths of pipes. FJ is pumping milk

SPOJ 913 QTREE系列- Query on a tree II (倍增LCA)

题目地址:QTREE2 - Query on a tree II LCA学了离线与在线转RMQ方法后就去做这道题,于是想了好长时间也没想到怎么做.看了题解都是用的倍增LCA..于是又去学了下倍增法求LCA,这才发现用倍增法做简直是水题...因为求路径的第k个点可以转化成求第k个父节点,然而倍增法的原理就是根据的父节点,于是这题就很容易解决了.. 求距离很好求.关键是求路径第k个点,显然这个点要么是u的第k个父节点,要么是v的第k个父节点,于是乎,先求一次LCA,判断是u还是v的,然后用倍增法找到

【bzoj4281】[ONTAK2015]Zwi?zek Harcerstwa Bajtockiego 树上倍增+LCA

题目描述 给定一棵有n个点的无根树,相邻的点之间的距离为1,一开始你位于m点.之后你将依次收到k个指令,每个指令包含两个整数d和t,你需要沿着最短路在t步之内(包含t步)走到d点,如果不能走到,则停在最后到达的那个点.请在每个指令之后输出你所在的位置. 输入 第一行包含三个正整数n,m,k(1<=m<=n<=1000000,1<=k<=1000000). 接下来n-1行,每行包含两个正整数x,y(1<=x,y<=n),描述一条树边. 接下来k行,每行两个整数d,t