HDU4008 Parent and son
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 1035 Accepted Submission(s): 249
Problem Description
Give you a tree with N vertices and N‐ 1 edges, and then ask you Q queries on “which vertex is Y's son that has the smallest number and which vertex is Y’s descendants that has the smallest number if we choose X as the root of the entire tree?”
Input
The first line of input is an integer T (T<=10) means the case number.
The first line of each test case contains N(2 ≤ N ≤ 100,000) and Q(1 ≤ Q ≤ 100,000).
Each of the following N ‐ 1 lines of the test case contains two integers a(1 ≤ a ≤ N) and b(1 ≤ b ≤ N) indicating an edge between a and b.
Each of the following Q lines of the test case contains two integers X(1 ≤ X ≤ N) and Y(1 ≤ Y ≤ N, Y ≠ X) indicating an query.
The first line of each test case contains N(2 ≤ N ≤ 100,000) and Q(1 ≤ Q ≤ 100,000).
Each of the following N ‐ 1 lines of the test case contains two integers a(1 ≤ a ≤ N) and b(1 ≤ b ≤ N) indicating an edge between a and b.
Each of the following Q lines of the test case contains two integers X(1 ≤ X ≤ N) and Y(1 ≤ Y ≤ N, Y ≠ X) indicating an query.
Output
For each query, output the Y's son which has the smallest number and Y's descendant that has the smallest number if X is the root of the entire tree. If Y has no sons then output “no answers!”. There is an empty line after each case.
Sample Input
1 7 3 1 2 1 5 2 3 2 4 5 6 5 7 1 2 5 3 3 2
Sample Output
3 3 no answers! 1 1
Source
**************************************************************
题目大意:给你一棵树,这个树的根节点不定。然后有Q次询问。对于每次询问,给定x和y。即当整棵树以x为根的时候,求y的所有儿子中最小的那个编号值以及y的所有
子孙中最小的编号值。
解题思路:
http://blog.csdn.net/hqd_acm/article/details/6750163我主要是参考了一篇文章,思路是他的,实现是我的。
还有不得不说的神乎其神的dfn时间戳数组。初识dfn数组是在前几天的图的连通性问题中见识到,当时觉得一个时间戳竟然如此好用。今天更感其神啊。当dfs一棵树的时候,
我们可以递归得到一个节点他是所有子孙中的最大的时间戳,把这个也记录下来。然后奇迹啊!我们可以在o(1)的时间内判断y是不是在x的子树下面。
其他的看那篇博客就好了。
本人代码附上:
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define INF 0x3f3f3f3f
#define N 100005
using namespace std;
vector<int>gra[N],ht;
int mindown[N],fa[N],minson[N][2],dfn[N],now,maxdfn[N];
int n,m;
/*mindown数组用来储存每个节点以下最小的子孙的值,fa数组储存每个节点的
父亲值,minson的两个值分别是每个节点下的最小和次小的儿子值,dfn神乎其神
的时间戳数组,now用来盖印时间戳,maxdfn数组用来储存每个节点子孙中的最大
的dfn值*/
void ini(void)//初始化
{
memset(fa,0,sizeof(fa));
memset(dfn,0,sizeof(dfn));
memset(maxdfn,0,sizeof(maxdfn));
now=0;
for(int i=1;i<=n;i++)
gra[i].clear();
}
void dfs(int s,int f)//预处理
{
fa[s]=f;
dfn[s]=maxdfn[s]=++now;
ht.clear();
mindown[s]=minson[s][0]=minson[s][1]=INF;
for(int i=0;i<gra[s].size();i++)
if(!fa[gra[s][i]])
ht.push_back(gra[s][i]);
gra[s]=ht;
for(int i=0;i<gra[s].size();i++)
{
int t=gra[s][i];
dfs(t,s);
mindown[s]=MIN(mindown[s],t);
mindown[s]=MIN(mindown[s],mindown[t]);
if(t<minson[s][0])
minson[s][1]=minson[s][0],minson[s][0]=t;
else if(t<minson[s][1])
minson[s][1]=t;
maxdfn[s]=MAX(maxdfn[s],maxdfn[t]);
}
}
int erfen(int x,int y)//二分查找儿子
{
int le=0,ri=gra[y].size(),mid;
while(1)
{
mid=(le+ri)>>1;
if(dfn[x]>=dfn[gra[y][mid]]&&dfn[x]<=maxdfn[gra[y][mid]])return gra[y][mid];
if(dfn[x]>maxdfn[gra[y][mid]])le=mid+1;
if(dfn[x]<dfn[gra[y][mid]])ri=mid-1;
}
}
void re(void)//输入
{
scanf("%d%d",&n,&m);
ini();
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
gra[a].push_back(b);
gra[b].push_back(a);
}
}
void run(void)//运行
{
dfs(1,-1);
int temp[2]={INF,INF};//temp表示1节点儿子中mindown的最小值和次小值
for(int i=0;i<gra[1].size();i++)
{
int t=gra[1][i];
if(mindown[t]<temp[0])
temp[1]=temp[0],temp[0]=mindown[t];
else if(mindown[t]<temp[1])
temp[1]=mindown[t];
}
for(int h=1;h<=m;h++)//m次询问
{
int x,y;
scanf("%d%d",&x,&y);
int fx=-1,fy=-1;
if(dfn[x]>dfn[y]&&dfn[x]<=maxdfn[y])//在o(1)的时间内知道x是不是y的子孙
fx=erfen(x,y);
if(dfn[y]>dfn[x]&&dfn[y]<=maxdfn[x])
fy=erfen(y,x);
if(fx==-1)//要么y是x的子孙,要么y和x不在一棵子树上面
{
if(mindown[y]==INF)printf("no answers!\n");
else printf("%d %d\n",minson[y][0],mindown[y]);
}
else//x是y的子孙,当y是否等于1的时候有特殊处理
{
if(y!=1)
{
if(fx!=minson[y][0])
printf("%d %d\n",MIN(minson[y][0],fa[y]),1);
else
{
if(gra[y].size()==1)
printf("%d %d\n",fa[y],1);
else
printf("%d %d\n",MIN(minson[y][1],fa[y]),1);
}
}
else
{
if(gra[y].size()==1)
printf("no answers!\n");
else
{
int a=temp[0];
if(a!=INF&&dfn[a]>=dfn[fx]&&dfn[a]<=maxdfn[fx])
a=temp[1];
int b=minson[1][0];
if(fx==minson[1][0])
b=minson[1][1];
printf("%d %d\n",b,MIN(a,b));
}
}
}
}
puts("");
}
int main()
{
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
re();
run();
}
}