[NOIP模拟][LCA]一样远

题目描述
企鹅国的城市结构是一棵树,有 N 座城市和 N-1 条无向道路,每条道路都一样长。豆豆和豆沙准备去参加 NOIP(National Olympiad in Informatics for Penguin),但是他们住在不同的地方,豆豆住在城市 A ,豆沙住在城市 B 。他们想找一个距离 A 和 B 一样远的集合地点,所以他们想知道有多少个城市满足这个要求?
由于他们会参加很多次 NOIP ,所以有很多个询问。
输入格式:
第一行一个整数 N,代表城市个数。
接下来 N-1 行,每行两个数字 F 和 T ,表示城市 F 和城市 T 之间有一条道路。
接下来一行一个整数 M 代表询问次数。
接下来 M 行,每行两个数字 A 和 B ,表示这次询问的城市 A 和城市 B(A可能与B相同)。
输出格式:
输出 M 行,每行一个整数表示到 A 和 B 一样远的城市个数。
样例输入1:

4
1 2
2 3
2 4
2
1 2
1 3

样例输出1:

0
2

样例输入2:

4
1 2
2 3
2 4
2
1 1
3 3

样例输出2:

4
4

数据范围:
对于 30% 的数据:N,M≤1000;
对于另外 10% 的数据:A=B;
对于另外 30% 的数据:保证树的形态随机;
对于 100% 的数据:1≤N,M≤100000。
题目分析
考试总结:考试时几乎写的是正解,就是最后找中点,脑子短路了,没有就像求lca一样倍增,结果却去dfs,写完才觉得时间复杂度不对。然后就TLE。
分析:我们考虑首先如果询问的两个点就是同一个点,那么答案就是n,这个从样例2就可以看出。对于两个点,要到这两个点的距离相等,只可能是这两个点的路径的中点以及这个中点所相连的所有子树和(除开路径方向的两个子树)。先预处理出每个节点size的大小(它自己再加上它所有子树的大小)。于是我们可以先用lca算出两点路径长度,然后选取深度较深的点让其往上跳len/2,就可以找到中点。统计答案分两种情况:一种是它们的中点就是它们的公共祖先(因为前面已经判断了两个点相同的情况,所以这里可以用深度相等来判断),此时的答案因为包括中点的父亲们,所以用总的n减去在路径上且比中点深度大1的两个点的size的大小;另一种是中点不是它们的公共祖先,那就直接求出在路径上且比中点深度大1的点,用中点的size减去这个点的size就是答案(因为路径的另一个来向就是中点的父亲,是都不计入答案的)。
附代码

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;

const int N=1e5+100;
int tot,n,m,a,b,c,nxt[N*2],first[N],to[N*2],dep[N],fa[N][25];
int sze[N],cha,len,ans,e,f;

int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

void create(int x,int y)
{
    tot++;
    nxt[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
}

void dfs(int u,int f)
{
    fa[u][0]=f;
    for(int i=1;i<=20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int e=first[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v!=f)
        {
            dep[v]=dep[u]+1;
            dfs(v,u);
            sze[u]+=sze[v];
        }
    }
}

int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    int d=dep[x]-dep[y];
    for(int i=20;i>=0;i--)
        if((1<<i)&d) x=fa[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int main()
{
    //freopen("equal.in","r",stdin);
    //freopen("equal.out","w",stdout);

    int x,y;
    n=readint();
    for(int i=1;i<n;i++)
    {
        x=readint();y=readint();
        create(x,y);
        create(y,x);
    }
    for(int i=1;i<=n;i++) sze[i]=1;
    dep[1]=0;
    dfs(1,0);
    m=readint();
    while(m--)
    {
        a=readint();b=readint();
        if(a==b)
        {
            printf("%d\n",n);
            continue;
        }
        c=lca(a,b);
        len=dep[a]+dep[b]-2*dep[c];
        if(len%2==1)
        {
            printf("0\n");
            continue;
        }
        if(dep[a]<dep[b]) swap(a,b);
        int d=len/2;
        if(dep[a]==dep[b])
        {
            e=a;f=b;
            for(int i=20;i>=0;i--)//用倍增来找点
                if((d-1)&(1<<i)) e=fa[e][i];
            for(int i=20;i>=0;i--)
                if((d-1)&(1<<i)) f=fa[f][i];
                ans=n-sze[e]-sze[f];
        }
        else
        {
            e=a;f=a;
            for(int i=20;i>=0;i--)
                if(d&(1<<i)) e=fa[e][i];
            for(int i=20;i>=0;i--)
                if((d-1)&(1<<i)) f=fa[f][i];
            ans=sze[e]-sze[f];
        }
        cout<<ans<<endl;//printf("%d\n",ans);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOIP(全青少年信息学奥林匹克竞赛)是中内最高水平的信息学竞赛之一,是计算机领域的重要赛事。针对NOIP模拟题,通常是为了帮助参赛者熟悉比赛形式和题型,提供足够的训练机会。 数据下载是NOIP比赛中的一个重要环节,因为参赛者需要根据提供的数据集进行程序开发和测试。数据下载一般通过网络进行,参赛者需要在指定的时间段内下载数据集到自己的计算机上。 在进行NOIP模拟题数据下载时,我们可以按照以下步骤进行操作: 1. 确认下载链接:NOIP官方会提供下载数据集的链接或者FTP地址,参赛者需要确认链接是否可用和正确。 2. 选择下载工具:根据自己的需求,参赛者可以选择合适的下载工具进行操作。常见的下载工具有浏览器内置下载工具、迅雷、IDM等,可以根据个人的习惯和需求选择合适的下载工具。 3. 打开下载工具:根据所选择的下载工具类型,打开对应的软件,进入下载界面。 4. 输入下载链接:将NOIP提供的数据集下载链接复制粘贴到下载工具的链接输入框中,点击确定或开始进行下载。 5. 等待下载完成:根据数据集的大小和网络速度不同,下载时间会有所变化。参赛者需要耐心等待下载完成,确保数据集完整地保存到自己的计算机上。 6. 验证数据完整性:下载完成后,参赛者需要验证数据集的完整性,确保所有文件都成功地保存到指定位置。可以进行文件大小的比对或者逐个文件的校验来检查数据完整性。 通过以上步骤,参赛者可以成功地进行NOIP模拟题数据的下载。在实际比赛中,一个高效的数据下载过程可以提高参赛者的准备时间和竞争力,确保能够充分利用所提供的数据集进行开发和测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值