NKOJ P3815 树上的询问 (LCA 倍增)

喜夏-厌秋 提交于 2019-11-26 14:51:48
评测说明 : 1000ms
问题描述

现有一棵 n 个节点的树,树上每条边的长度均为 1。给出 m 个询问,每次询问两个节 点 x,y,求树上到 x,y 两个点距离相同的节点数量。 

输入格式

第一个整数 n,表示树有 n 个点。
接下来 n-1 行每行两整数 a,b,表示从 a 到 b 有一条边。
接下来一行一个整数 m,表示有 m 个询问。
接下来 m 行每行两整数 x,y,询问到 x 和 y 距离相同的点的数量。 

输出格式

共 m 行,每行一个整数表示询问的答案。 

样例输入


1 2 
1 3 
2 4 
2 5 
3 6 
3 7 

1 2 
4 5
2 3 

 
 
 
思路: 被坑了好久 一直没调出来  复习了一波LCA 后 终于A 了 注意 倍增的用法 即GOUP 操作
 
顺便复习一下 距离倍增 
code:
g[x][i]=g[x][i-1]+g[fa[x][i-1]][i-1];

dis 求法

for(i=0;i<=ss;i++)
    if(k&(1<<i))dis+=g[x][i],x=fa[x][i];
if(x==y)return dis;
for(i=s;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
        {
            dis+=g[x][i];x=fa[x][i];

            dis+=g[y][i];y=fa[y][i];
        }
    return dis+=g[x][0]+g[y][0];

 

 
code:
//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 600000
int f[maxnn][100];
int las[maxnn],nex[maxnn],en[maxnn],tot;
int n,m;
int dep[maxnn];
int x,y;
int size[maxnn];
void dfs(int v,int fa)
{
    dep[v]=dep[fa]+1;
    f[v][0]=fa;
    int s=ceil(log2(n));
    for(int i=1;i<=s;i++)
    {
        f[v][i]=f[f[v][i-1]][i-1];
    }
    for(int i=las[v];i;i=nex[i])
    {
        int u=en[i];
        if(u!=fa)
        {
            dfs(u,v);
            size[v]+=size[u];
        }
    }
    return ;
}
void add(int a,int b)
{
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
}
int goup(int x,int s)
{
    int k=ceil(log2(n));
    for(int i=0;i<=k;i++)
    {
        if((s&(1<<i)))
        {
            x=f[x][i];
        }
    }
    return x;
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    x=goup(x,dep[x]-dep[y]);
    if(x==y) return y;
    int s=ceil(log2(dep[x]));
    for(int i=s;i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) size[i]=1;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int k1=0,k=0;
        scanf("%d%d",&x,&y);
        if(y==x) {cout<<n<<endl;continue;}
        if(dep[x]==dep[y])
        {
            int k=dep[x]-dep[lca(x,y)];
            int k1=n-size[goup(x,k-1)]-size[goup(y,k-1)];
            cout<<k1<<endl;
            continue;
        }
        if((abs((dep[x]-dep[y])))&1) {cout<<0<<endl;continue;}
        if(dep[x]<dep[y])
        swap(x,y);
        k=(dep[y]+dep[x]-2*dep[lca(x,y)])/2;
        int p1=goup(x,k-1);int p2=goup(x,k);
        k1=size[p2]-size[p1];
        cout<<k1<<endl;
        
    } 
 } 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!