bzoj1787: [Ahoi2008]Meet 紧急集合

lca。

3个点分别lca,可以知道,深度最深的lca就是答案。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 500000 + 10;
const int maxm = 1000000 + 10;
const int maxl = 22;

int g[maxn],v[maxm],next[maxm],eid;
int anc[maxn][maxl],h[maxn];
int q[maxn];
int A,B,C,n,m;

void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; next[eid]=g[b]; g[b]=eid++;
}

void build() {
    scanf("%d%d",&n,&m);
    memset(g,-1,sizeof(g));
    for(int i=1,u,v;i<n;i++) {
        scanf("%d%d",&u,&v);
        addedge(u,v);
    }    
}

void bfs() {
    int l,r,u;
    l=r=0;
    h[1]=1;q[r++]=1; anc[1][0]=1;
    while(l<r) {
        u=q[l++];
        for(int i=g[u];~i;i=next[i]) if(v[i]!=anc[u][0]) {
            anc[v[i]][0]=u;
            q[r++]=v[i];    
            h[v[i]]=h[u]+1;
        }
    }
}

void up(int &a,int H) {
    for(int i=maxl-1;i>=0;i--) 
        if(h[anc[a][i]]>=H) a=anc[a][i];
}

int LCA(int a,int b) {
    if(h[a]!=h[b]) {
        if(h[a]>h[b]) up(a,h[b]);
        else up(b,h[a]);    
    }
    if(a==b) return a;
    for(int l=maxl-1;l>=0;l--) 
        if(anc[a][l]!=anc[b][l]) {
            a=anc[a][l];
            b=anc[b][l];    
        }
    return anc[a][0];
}

int dis(int a,int b) {
    int p=LCA(a,b);
    return h[a]+h[b]-2*h[p];
}

void solve() {
    for(int i=1;i<=m;i++) {
        int p,p1,p2,p3;
        scanf("%d%d%d",&A,&B,&C);
        p1=LCA(A,B),p2=LCA(A,C),p3=LCA(B,C);
        if(p1==p2) p=p3;
        else if(p1==p3) p=p2;
        else p=p1;
        printf("%d %d
",p,dis(p,A)+dis(p,B)+dis(p,C));    
    }
}


void predo() {
    bfs();    
    for(int i=1;i<maxl;i++) 
    for(int u=1;u<=n;u++) 
        anc[u][i]=anc[anc[u][i-1]][i-1];
}

int main() {
    build();
    predo();
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/invoid/p/5571606.html