祖孙询问

题目描述 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;
}

总结

转载于:https://www.cnblogs.com/FYH-SSGSS/p/7811066.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值