Codeforces 832D(Misha, Grisha and Underground,LCA)

題意:在一棵生成樹上,給出了三個點,求三個點之間最大的相交點數,CF難度1900。

題解:求出三個lca,並取深度最大的那個,就是我們要的三岔路口K,然後分別求出K到a,b,c三點的路徑長度,取最大值+1就是答案。為什麼是取深度最大的呢?因為只有當深度是最大的時候設該點為K,這個K為三岔路口,每一個a,b,c到K的距離都不會用重複,否則如果取的不是最深的,可能造成重複的情況,這個需要避免。然後找到這個K之後,ans就是a,b,c三點分別到K的距離+1即可(+1是因為本身也算)。

一開始沒做出來的原因:不知道如何找這個岔口….以為需要把岔口當做root來弄,然後就需要一次又一次的重複更新建立LCA表,就很麻煩。其實求岔口只需要以1作為root,然後a,b,c三個點兩兩求LCA然後取深度最大的LCA就行了….樹上每2個點的距離dis(u,v)=depth[u]+depth[v]-2*depth(LCA(u,v)],好吧是我菜了

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int tot,head[maxn];
struct E{
    int to,next;
}edge[maxn<<1];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m,a[maxn],fa[maxn][40],depth[maxn],vis[maxn];
void dfs(int s,int step){
    depth[s]=step;vis[s]=1;
    for(int i=head[s];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!vis[v]) fa[v][0]=s,dfs(v,step+1);
    }
}
void bz(){
    for(ll j=1;j<=30;j++){
        for(ll i=1;i<=n;i++){
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
}
ll LCA(ll u,ll v){
    if(depth[u]<depth[v]) swap(u,v);
    ll dc=depth[u]-depth[v];
    for(ll i=0;i<30;i++){
        if((1<<i)&dc){
            u=fa[u][i];
        }
    }
    if(u==v) return u;
    for(ll i=29;i>=0;i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    u=fa[u][0];
    return u;
}
int dis(int u,int v){
    return depth[u]+depth[v]-2*depth[LCA(u,v)];
}
int main(){
    scanf("%d%d",&n,&m);mem(head,-1);
    for(int i=2;i<=n;i++){
        int x;scanf("%d",&x);
        add(i,x);add(x,i);
    }    
    dfs(1,1);
    bz();
    while(m--){
        int a,b,c;scanf("%d%d%d",&a,&b,&c);
        int l1=LCA(a,b);
        int l2=LCA(a,c);
        int l3=LCA(b,c);
        if(depth[l2]>depth[l1]) l1=l2; 
        if(depth[l3]>depth[l1]) l1=l3;
        cout<<max(dis(l1,a),max(dis(l1,b),dis(l1,c)))+1<<endl; 
    }
}

View Code