zoukankan      html  css  js  c++  java
  • 倍增

    LCA

    描述

    给一棵有根树,以及一些询问,每次询问树上的 2 个节点 A、B,求它们的最近公共祖先.
    !强制在线!

    输入

    第一行一个整数 N.
    接下来 N 个数,第 i 个数 F i 表示 i 的父亲是 F i. 若 F i = 0,则 i 为树根.
    接下来一个整数 M.
    接下来 M 行,每行 2 个整数 A、B,询问节点(A xor LastAns)、(Bxor LastAns)的最近公共祖先. 其中 LastAns 为上一个询问的答案,一开始 LastAns = 0.

    输出

    对每一个询问输出相应的答案.

    样例

    Sample Input
    10
    0 1 2 3 2 4 2 5 4 9
    10
    3 9
    2 7
    7 8
    1 1
    0 6
    6 11
    6 3
    10 7
    2 15
    7 7
    Sample Output
    3
    1
    4
    5
    2
    4
    2
    5
    2
    5
    

    提示

    30%,n,m≤1000
    100% n,m≤100,000


    既然名字都叫LCA了那当然是求LCA啦然而某些题……
    鬼知道是怎么强制在线的。
    不管那么多,在线的LCA有2种求法:转换成RMQ,或者倍增跳跳跳。
    由于只会倍增的原因在这里选择倍增。
    关键操作主要有DFS和lca。
    DFS预处理出每个点的深度和倍增数组,
    lca中首先让深度最大的点向上跳直到与另一个点平齐,
    如果不同的话2个点一起肛肛到你听到为止用倍增数组跳,跳到相等为止。
    代码实现算是简单的
    代码蒯上

    #include<iostream>
    #include<iomanip>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int gotcha()
    {
    	register int _a=0;bool _b=1;register char _c=getchar();
    	while(_c<'0' || _c>'9'){if(_c=='-')_b=0;_c=getchar();}
    	while(_c>='0' && _c<='9')_a=_a*10+_c-48,_c=getchar();
    	return _b?_a:-_a;
    }
    const int _ = 100002;
    struct edge{int to,ne;edge(){to=ne=0;}}e[_*2];
    int he[_]={0},ecnt=0;
    void add(int fr,int to)
    {e[++ecnt].to=to,e[ecnt].ne=he[fr],he[fr]=ecnt;}
    int fa[_][20],dep[_],n;
    bool ed[_]={0};
    void DFS(int d)
    {
    	ed[d]=1;
    	int i,j;
    	for(i=1;i<=18;i++)if(dep[d]>=(1<<i))fa[d][i]=fa[fa[d][i-1]][i-1];
    	for(i=he[d];i;i=e[i].ne)
    		if(!ed[j=e[i].to])fa[j][0]=d,dep[j]=dep[d]+1,DFS(j);
    }
    int finder(int a,int b)
    {
    	if(dep[a]<dep[b])swap(a,b);
    	int i,cha=dep[a]-dep[b];
    	for(i=0;i<=18;i++)
    	{
    		if(cha & (1<<i))a=fa[a][i];
    		if(a==b)return a;
    	}
    	for(i=18;i>=0;i--)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
    	return fa[a][0];
    }
    int main()
    {
    	register int i,j,t,la=0;
    	n=gotcha();
    	for(i=1;i<=n;i++)j=gotcha(),add(i,j),add(j,i);
    	for(i=1;i<=n;i++)if(!ed[i])DFS(i);
    	t=gotcha();
    	while(t--)
    	{
    	   	i=gotcha() xor la,j=gotcha() xor la;
    		la=finder(i,j),printf("%d
    ",la);
    	}
    	return 0;
    }
    
  • 相关阅读:
    洛谷 P2384 最短路
    洛谷 P2910 [USACO08OPEN]寻宝之路Clear And Present Danger
    POJ 3264 Balanced Lineup
    洛谷 P1892 团伙
    洛谷 P1724 东风早谷苗
    P1129 [ZJOI2007]矩阵游戏
    P1894 [USACO4.2]完美的牛栏The Perfect Stall
    Poj 3041 Asteroids
    P3377 【模板】左偏树(可并堆)
    P1613 跑路
  • 原文地址:https://www.cnblogs.com/finder-iot/p/7622797.html
Copyright © 2011-2022 走看看