洛谷 P3379 LCA模板

本人最近刚接触到LCA,先是在vjudge的团队里做到了一到倍增LCA找父亲(codeforces 519E),然后求出有多少个点到访问的x,y这两个节点的距离相同。

 

 

洛谷题号:CF519E                                                                           

链接:https://www.luogu.org/problemnew/show/CF519E 

 

 

我有一个程序疯狂无限制第7个点爆MLE到现在都不知道为什么。   

代码请见:https://www.luogu.org/discuss/show?postid=48843 

 

 

希望有大佬能够指点迷津。 可以在洛谷评论也可以在这里评论,或者私信我的qq也行             

QQ:2320993191

 

但是虽然说是一直MLE过不去这道题目,但是对LCA我初步有了一定的理解,然后我就按耐不住激动地心情,来到洛谷做了一下模板LCA。  

这里我要讲两个注意点:

1.在我们在做dfs预处理f数组的时候,i不能倒着扫,因为每一个f[x][i]都来源于比自己要小的f[f[x][i-1]][i-1],所以如果倒着扫就会出现问题。我刚开始也就是因为这个错了。

                                       

2.当我们在把x节点和y节点跳到同一个深度以及之后达到同一深度再往上跳的时候,i都需要倒着扫,这里我们需要想一下,我举一个例子,如果我现在需要向上跳5个深度,那么如果我i=1的时候跳(1<<1)也就是2个深度的时候,我还需要跳3个深度,但是当我下一次要跳的时候 i已经等于2了,又因为(1<<2)等于4了,已经超过了3个深度所以已经不能跳了。所以必须是要倒着扫的,其次我们在想一下,即使我们倒着扫,我们也无法判断,这次往上跳完了之后到底是已经在我们所需要求的LCA只上,还是恰好是我们需要求的LCA,所以当f[x][i]==f[y][i]的时候我们干脆不跳,这样等我们操作完了之后,只需要在往上跳一个深度,那么那个节点就一定是我们所想要的LCA. 下面是我的AC代码,大家可以参考一下。如果有什么地方有问题欢迎大家提出,也随时欢迎大家来找我一起讨论OI问题,其他问题也可以啦哈哈哈哈哈哈哈,比如说抑郁不得志(这么大佬的你们肯定不会抑郁不得志的),我可以帮你解脱烦恼O(∩_∩)O哈哈~

 

(邻接表记录边的数组一定要开两倍!!!!因为是无向图,每条边会进两次)

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1000010;
int n,m,s,x,y,ans,top;
int first[N],next[N],get[N],deep[N];
int f[N][32];
void add(int x,int y){
    get[++top]=y;
    next[top]=first[x];
    first[x]=top;
}
void dfs(int x,int fa,int deep_){
    deep[x]=deep_;
    f[x][0]=fa;
    for (int i=1;(1<<i)<=deep_;++i)
    f[x][i]=f[f[x][i-1]][i-1];
    for (int i=first[x];i;i=next[i]){
        int v=get[i];
        if (v==fa) continue;
        dfs(v,x,deep_+1);
    }
}
void LCA(int a,int b){
    if (deep[a]>deep[b]) swap(a,b); //a浅 b深
    for (int i=31;i>=0;--i){
        if (deep[b]-(1<<i)<deep[a]) continue;
        b=f[b][i];
    }
    if (a==b) {
        ans=a;
        return;
    }
    for (int i=31;i>=0;--i){
        if(f[a][i]==f[b][i]) continue;
        a=f[a][i];
        b=f[b][i];
    }
    ans=f[a][0];
}
int main(){
    //freopen(".in","r",stdin);
    scanf("%d%d%d",&n,&m,&s);
    for (int i=1;i<=n-1;++i){
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(s,0,1);
    for (int i=1;i<=m;++i){
        scanf("%d%d",&x,&y);
        LCA(x,y);
        printf("%d\n",ans);
    }
}

 

转载于:https://www.cnblogs.com/Dilemma/p/9307455.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值