LCA 约会

    

问题 C: 约会

时间限制: 2 Sec   内存限制: 256 MB

题目描述

输入

输出

样例输入

4
1 2
1 3
2 4
1
2 3

样例输出

1

提示

    一道不错的LCA的题。考试时想到正解,无奈打错LCA,超时了35分。。(一个新坑)

    这里是需要讨论的。

    一,如果求出的路径长为奇数,一定没有合法解。

    二,如果x==y,输出n。

    三,如果dep[x]==dep[y],设k=LCA(x,y),fx为x祖先,且dep[fx]==dep[k]+1,fy同理,

           则ans=n-size[fx]-size[fy],

    四,剩下就是正常情况了,设h为x,y距离,(设dep[x]>dep[y])k为x祖先,dep[k]==dep[x]-h/2.

           ans=size[k]-size[fx],fx为x祖先,dep[fx]==dep[k]+1.

    神犇ljy云:“我如果会LCA,我今天就AK了。”然并卵,我也是啊。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100000
using namespace std;
int read()
{
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
    while(x>='0'&&x<='9'){sum=(sum<<1)+(sum<<3)+x-'0';x=getchar();}
    return sum*f;
}
int n,m,adj[N+5],e;
int f[N+5],dep[N+5],size[N+5],p[100005][20];
struct road
{
    int v,next;
}lu[N*2+5];
void add(int u,int v){lu[++e].v=v;lu[e].next=adj[u];adj[u]=e;}
void dfs(int x,int deep)
{
    size[x]=1;
    dep[x]=deep;
    for(int i=adj[x];i;i=lu[i].next)
    {
        int to=lu[i].v;
        if(to!=f[x])
        {
            f[to]=x;
            dfs(to,deep+1);
            size[x]+=size[to];
        }
    }
}
int get(int x,int y)
{
    int i,j;
    if(dep[x]<dep[y])swap(x,y);
    for(i=0;(1<<i)<=dep[x];i++);
    i--;
    for(j=i;j>=0;j--)
        if(dep[x]-(1<<j)>=dep[y])
           x=p[x][j];
    if(x==y)return x;
    for(j=i;j>=0;j--)
       if(p[x][j]!=-1&&p[x][j]!=p[y][j])
       {
            x=p[x][j];
            y=p[y][j];
       }
    return f[x];  
}
void init()
{
    for(int j=0;(1<<j)<=n;j++)
       for(int i=1;i<=n;i++)
          p[i][j]=-1;
    for(int i=1;i<=n;i++)p[i][0]=f[i];
    for(int j=1;(1<<j)<=n;j++)
       for(int i=1;i<=n;i++)
          if(p[i][j-1]!=-1)
             p[i][j]=p[p[i][j-1]][j-1];
}
int zhao(int x,int h)
{
    int i,j;
    for(i=0;(1<<i)<=dep[x];i++);
    i--;
    for(j=i;j>=0;j--)
       if(h-(1<<j)>=0)
       {
           h-=(1<<j);
           x=p[x][j];
       }
    return x;
}
int main()
{
//  freopen("date.in","r",stdin);
//  freopen("date.out","w",stdout);
    n=read();
    int x,y;
    for(int i=1;i<n;i++)
    {
        x=read();y=read();
        add(x,y);add(y,x);
    }
    f[1]=0;
    dfs(1,1);
    init();
    m=read();
    int w,q;
    while(m--)
    {
        x=read();y=read();
        if(x==y){printf("%d\n",n);continue;}
        int k=get(x,y);
        int h=dep[x]+dep[y]-2*dep[k];
        if(h%2){printf("0\n");continue;}
        if(dep[x]==dep[y])
        {
            w=zhao(x,dep[x]-dep[k]-1);
            q=zhao(y,dep[y]-dep[k]-1);
            printf("%d\n",n-size[w]-size[q]);
        }
        else
        {
            if(dep[x]>dep[y])swap(x,y);
            q=zhao(y,h/2),w=zhao(y,h/2-1);
            printf("%d\n",size[q]-size[w]);
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值