祖孙询问
题目描述 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\n");
else if(l[a]<=r[b] && l[a]>l[b])printf("2\n");
else printf("0\n");
}
return 0;
}