祖孙询问
Description
已知一棵(n)个节点的有根树。有(m)个询问。每个询问给出了一对
节点的编号(x)和(y),询问(x)与(y)的祖孙关系。
Input Format
输入第一行包括一个整数n表示节点个数。
接下来n行每行一对整数对(a)和(b)表示(a)和(b)之间有连边。如果(b)是(-1),那么(a)就是树的根。
第(n+2)行是一个整数(m)表示询问个数。
接下来(m)行,每行两个正整数(x)和(y)。
Output Format
对于每一个询问,输出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
Hint
对于(30%)的数据,(n,m≤1000)。
对于(100%)的.据,(n,m≤40000),每个节点的编号都不超过(40000)。
Solution
首先这题应该是一个(LCA)模板题,但是我们这里考虑用(dfs)来做。
其实这题的主要思想应该是一个时间戳的应用。
我们记录当前搜索到这个点的时间(变灰时间)和递归到这个点的时间(变黑时间)
然后我们将变灰时间和变黑时间进行比较就可以找出两个点的关系
#include<bits/stdc++.h>
#define Re register int
using namespace std;
int N,M,a,b,Num,head[80005],Start,Dep[40005],Ret[40005],Time;
bool Check[40005];
struct Edge{
int To,Next;
}edge[80005];//双向建边数组记得开两倍
inline void Add_Edge(int u,int v){
edge[++Num].Next=head[u];
edge[Num].To=v;
head[u]=Num;
}
inline void Dfs(int Now){
Dep[Now]=++Time; Check[Now]=true; //变灰的时间
for (Re i=head[Now];i;i=edge[i].Next) if (!Check[edge[i].To]) Dfs(edge[i].To);
Ret[Now]=++Time; //变黑的时间
}
int main(){
scanf("%d",&N);
for (Re i=1; i<=N; ++i){
scanf("%d%d",&a,&b);
if (b==-1) Start=a;
else {
Add_Edge(a,b);Add_Edge(b,a);
}
}
Dfs(Start);
scanf("%d",&M);
for (Re i=1; i<=M; ++i){
scanf("%d%d",&a,&b);
if (Dep[a]<Dep[b]&&Ret[a]>Ret[b]) printf("1
");
else if (Dep[a]>Dep[b]&&Ret[a]<Ret[b]) printf("2
");
else printf("0
");
}
return 0;
}
第二种方法......
就是正版一点的(LCA)
(LCA)模板在上面随笔的转发
用(LCA)判断两个点的高低,然后让低的那个点往上跳,一直跳到两个点在同一层,记住这里指的是同一层;
然后在判断这两个点是否重合,如果重合就可以输出答案
答案是(1)还是(2)那么就是看两个点的高低......
#include<bits/stdc++.h>
#define Re register int
using namespace std;
int N,M,a,b,Num,head[80005],Root;
int f[40005][21],d[40005];
bool Check[3];
struct Edge{
int To,Next;
}edge[80005];
inline void Add_Edge(int u,int v){
edge[++Num].Next=head[u];
edge[Num].To=v;
head[u]=Num;
}
inline void dfs(int Now,int fa){
d[Now]=d[fa]+1; f[Now][0]=fa;
for (Re i=1; (1<<i)<=d[Now]; ++i) f[Now][i]=f[f[Now][i-1]][i-1];
for (Re i=head[Now];i;i=edge[i].Next) if (edge[i].To^fa) dfs(edge[i].To,Now);
}
inline void LCA(int a,int b){
if (d[a]>d[b]) swap(a,b),Check[0]=true;
for (Re i=20; i>=0; --i) if (d[a]<=d[f[b][i]]) b=f[b][i];
if (a==b) Check[1]=true;
}
int main(){
scanf("%d",&N);
for (Re i=1; i<=N; ++i){
scanf("%d%d",&a,&b);
if (b==-1) Root=a;
Add_Edge(a,b);
Add_Edge(b,a);
}
dfs(Root,0);
scanf("%d",&M);
for (Re i=1; i<=M; ++i){
memset(Check,false,sizeof(Check));
scanf("%d%d",&a,&b);
LCA(a,b);
if (Check[0]&&Check[1]) printf("2
");
else if (!Check[0]&&Check[1]) printf("1
");
else printf("0
");
}
return 0;
}