祖孙询问

题目描述 Description###

已知一棵(n) 个节点的有根树。有(m) 个询问。每个询问给出了一对节点的编号(x)(y) ,询问x与y的祖孙关系。

输入描述 Input Description###

输入第一行包括一个整数n表示节点个数。
接下来(n) 行每行一对整数对(a)(b) 表示(a)(b) 之间有连边。如果(b)(-1) ,那么a就是树的根。
(n+2) 行是一个整数(m) 表示询问个数。
接下来(m) 行,每行两个正整数(x)(y)

输出描述 Output Description###

对于每一个询问,输出1:如果(x)(y) 的祖先,输出2:如果(y)(x) 的祖先,否则输出(0)

样例输入 Sample Input###

10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19

样例输出 Sample Output###

1
0
0
0
2

数据范围及提示 Data Size & Hint###

数据范围:对于30%的数据,(n,m≤1000) ,对于100%的.据,(n,m≤40000) ,每个节点的编号都不超过(40000)

之前的一些废话###

题解###

对于一棵树求一下(dfs) 序,根据(dfs) 的顺序,每一个点的子孙都属于(dfs) 序中的一个区间,所以在(dfs) 时维护即可。

代码###

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> PII;
#define X first
#define Y second
#define mp make_pair
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=40010;
int n,first[maxn],ce=-1,q,a,b,rt,l[maxn],r[maxn],dfs_clock,m;
struct Edge
{
	int u,v,next;
	Edge() {}
	Edge(int _1,int _2,int _3):u(_1),v(_2),next(_3) {}
}e[maxn<<1];
void addEdge(int a,int b)
{
	e[++ce]=Edge(a,b,first[a]);first[a]=ce;
	e[++ce]=Edge(b,a,first[b]);first[b]=ce;
}
void dfs(int now,int fa)
{
	l[now]=++dfs_clock;
	for(int i=first[now];i!=-1;i=e[i].next)
		if(e[i].v!=fa)dfs(e[i].v,now);
	r[now]=dfs_clock;
}
int main()
{
	mem(first,-1);
	n=read();
	for(int i=1;i<=n;i++)
	{
		a=read(),b=read();
		if(b!=-1)addEdge(a,b);
		else rt=a;
	}
	dfs(rt,-1);
	m=read();
	while(m--)
	{
		a=read();b=read();
		if(l[b]<=r[a] && l[b]>l[a])printf("1
");
		else if(l[a]<=r[b] && l[a]>l[b])printf("2
");
		else printf("0
");
	}
	return 0;
}

总结###

原文地址:https://www.cnblogs.com/FYH-SSGSS/p/7811066.html