CF 519E(树上倍增求lca)

传送门:A and B and Lecture Rooms

题意:给定一棵树,每次询问到达点u,v距离相等的点有多少个。

分析:按情况考虑:

1.abs(deep[u]-deep[v])%2==1时,必定不存在到达u,v距离相等的点。

2.如果deep[u]==deep[v]时,ans=n-num[lca(u,v)u在的儿子树]-num[lca(u,v)v在的儿子树]。

3.如果deep[u]!=deep[v]时,在u到v的路径中找出到达u,v相等的节点x,则ans=num[x]-num[u在的x儿子树].

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <map>
#define N 200010
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
struct edge
{
    int v,next;
    edge() {}
    edge(int v,int next):v(v),next(next) {}
} e[N];
int head[N],tot;
int num[N],deep[N];
int fa[N][20];
void init()
{
    memset(head,-1,sizeof(head));
    tot=0;
}
void addedge(int u,int v)
{
    e[tot]=edge(v,head[u]);
    head[u]=tot++;
}
void dfs(int x,int f)
{
    for(int i=1; i<20; i++)
    {
        if(deep[x]<(1<<i))break;
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    for(int i=head[x]; ~i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==f)continue;
        fa[v][0]=x;
        deep[v]=deep[x]+1;
        dfs(v,x);
        num[x]+=num[v];
    }
}
int lca(int x,int y)
{
    if(deep[x]<deep[y])swap(x,y);
    int t=deep[x]-deep[y];
    for(int i=0; i<=19; i++)
        if((1<<i)&t)x=fa[x][i];
    for(int i=19; i>=0; i--)
    {
        if(fa[x][i]!=fa[y][i])
        {
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    if(x==y)return x;
    return fa[x][0];
}
int main()
{
    int n,m;
    while(scanf("%d",&n)>0)
    {
        init();
        for(int i=1; i<n; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        for(int i=1;i<=n;i++)num[i]=1;
        deep[1]=1;
        dfs(1,0);
        scanf("%d",&m);
        while(m--)
        {
            int x,y;
            scanf("%d%d", &x,&y);
            if(deep[x]<deep[y])swap(x,y);
            if((deep[x]-deep[y])&1) printf("0
");
            else
            {
                int xy=lca(x, y),tx=x;
                int t=(deep[x]+deep[y]-2*deep[xy])/2-1;
                for(int i=0;i<20;i++)if(t&(1<<i))x=fa[x][i];
                if(deep[tx]==deep[y])
                {
                    t=deep[y]-deep[xy]-1;
                    for(int i=0;i<20;i++)if(t&(1<<i))y=fa[y][i];
                    printf("%d
",n-num[x]-num[y]);
                }
                else printf("%d
", num[fa[x][0]]-num[x]);
            }
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/lienus/p/4306534.html