您的位置:首页 > 编程语言 > C语言/C++

Cpp环境【CQ-NOIP2016四校联考模拟题(一)P3】树上的询问

2016-10-17 19:55 344 查看
【问题描述】


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

【输入格式】


  第一个整数 n, 表示树有 n 个点。

  接下来 n-1 行每行两整数 a, b, 表示从 a 到 b 有一条边。

  接下来一行一个整数 m, 表示有 m 个询问。

  接下来 m 行每行两整数 x, y, 询问到 x 和 y 距离相同的点的数量。

【输出格式】


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

【输入样例】


7

1 2

1 3

2 4

2 5

3 6

3 7

3

1 2

4 5

2 3

【输出样例】


0

5

1

【数据范围】


对于 30%的数据, 满足 n≤50, m≤50

对于 60%的数据, 满足 n≤1000, m≤1000

对于 100%的数据, 满足 n≤100000, m≤100000

【来源】


noip2016四校联考,巴蜀命题

#include<cctype>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#define maxn 100005
using namespace std;
vector<int>g[maxn];
int n,m,fa[maxn],depth[maxn],dist[maxn],sz[maxn],depthnum[maxn];
int marka,markb;
//depthnum[i]=深度为i的节点数量
//dist[i]=所有深度小于i的节点的数量
//sz[i]=以节点i为根的子树的节点总数
void read(int &x)
{
x=0;
char ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
}

void build_tree(int i)
{
for(int j=0;j<g[i].size();j++)
{
int k=g[i][j];
if(fa[k])continue;
fa[k]=i;depth[k]=depth[i]+1;
build_tree(k);
sz[i]+=sz[k];
}
sz[i]++;//i节点包括在以i为根的子树里
}

int LCA(int a,int b)
{
while(depth[a]>depth[b])    a=fa[a];
while(a!=b) marka=a,a=fa[a],markb=b,b=fa[b];
return a;
}

void solve()
{
read(m);
while(m--)
{
int a,b;
read(a);read(b);
if(depth[b]>depth[a])   swap(a,b);

if(a==b)    printf("%d\n",n);
else
{
int root=LCA(a,b),da=depth[root]-depth[a],db=depth[root]-depth[b];
if((da+db)%2)   printf("0\n");
else if(depth[a]==depth[b]) printf("%d\n",n-sz[marka]-sz[markb]);
else
{
int d=da+db;//a与b的距离
int mid=depth[a]+d/2,now=a,last=a;
while(depth[now]!=mid)  last=now,now=fa[now];
printf("%d\n",sz[now]-sz[last]);
}
}
}
}

int main()
{
//  freopen("in.txt","r",stdin);
//  freopen("Tree.out","w",stdout);
read(n);
for(int i=1;i<n;i++)
{
int x,y;
read(x);read(y);
g[x].push_back(y);
g[y].push_back(x);
}
fa[1]=1;
build_tree(1);
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  cpp noip2016