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(); } }