链接:http://acm.hdu.edu.cn/showproblem.php?pid=4008
题意很简单,给出一棵树,找出以x节点为根节点的情况下,y节点的最小儿子节点和最小子孙节点,每次进行一次搜索肯定是不行的,所以我们考虑只进行一次搜索,利用得到的结论去找到在其他情况下的解,先在以1为根节点的树中进行一遍深度优先搜索,记录下son[u][0](以u为根节点的子树中标号最小的子节点点)son[u][1](以u为根节点的树中标号次小的子节点)因为在选定不同的根节点导致图旋转的过程中,这两个节点最多有一个会变成u的父节点,所以直接确定另一个就可以了。low[u][0](以u为节点的子树中,标号最小的子孙节点),low[u][1](以u为根的所有的子树中所有low[v][0]的次小值,注意仔细理解这句话的意义,因为图旋转的过程中最多会有一棵子树在u节点的上方,所以同样可以确定另一个),具体的有一些细节的实现可以看代码
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N 100005 5 #define inf 0x7fffffff 6 using namespace std; 7 int son[N][2],low[N][2]; 8 int pre[N]; 9 int head[N],cnt; 10 struct node 11 { 12 int v,next; 13 }; 14 node e[N*2]; 15 bool used[N]; 16 int min(int a,int b) 17 { 18 return a<b?a:b; 19 } 20 void add(int u,int v) 21 { 22 e[cnt].v=v,e[cnt].next=head[u],head[u]=cnt++; 23 e[cnt].v=u,e[cnt].next=head[v],head[v]=cnt++; 24 } 25 void init() 26 { 27 memset(head,-1,sizeof(head)); 28 memset(pre,-1,sizeof(pre)); 29 memset(used,0,sizeof(used)); 30 cnt=0; 31 int i; 32 for(i=0;i<N;i++) 33 { 34 son[i][0]=son[i][1]=inf; 35 low[i][0]=low[i][1]=inf; 36 } 37 } 38 void dfs(int u,int f) 39 { 40 int i,v; 41 pre[u]=f; 42 used[u]=true; 43 for(i=head[u];i>=0;i=e[i].next) 44 { 45 v=e[i].v; 46 if(used[v]) 47 continue; 48 if(v!=f) 49 dfs(v,u); 50 if(v<son[u][1]) 51 son[u][1]=v; 52 if(son[u][0]>son[u][1]) 53 swap(son[u][0],son[u][1]); 54 int minn=low[v][0]<v?low[v][0]:v; 55 if(minn<low[u][1]) 56 low[u][1]=minn; 57 if(low[u][1]<low[u][0]) 58 swap(low[u][1],low[u][0]); 59 } 60 } 61 int find(int x,int y) 62 { 63 while(pre[x]!=x) 64 { 65 if(pre[x]==y) 66 return x; 67 x=pre[x]; 68 } 69 return 0; 70 } 71 int main() 72 { 73 int t,n,x,y,q,ans1,ans2,temp,i; 74 scanf("%d",&t); 75 while(t--) 76 { 77 scanf("%d%d",&n,&q); 78 init(); 79 for(i=1;i<n;i++) 80 { 81 scanf("%d%d",&x,&y); 82 add(x,y); 83 } 84 dfs(1,1); 85 for(i=1;i<=q;i++) 86 { 87 scanf("%d%d",&x,&y); 88 ans1=ans2=inf; 89 temp=find(x,y); 90 if(temp==0) 91 { 92 ans1=son[y][0]; 93 ans2=low[y][0]; 94 } 95 else 96 { 97 if(y!=1) 98 { 99 if(temp==son[y][0]) 100 ans1=min(son[y][1],pre[y]); 101 else 102 ans1=min(son[y][0],pre[y]); 103 ans2=1;//这个可以直接确定 104 } 105 else 106 { 107 if(temp==son[y][0]) 108 ans1=son[y][1]; 109 else 110 ans1=son[y][0]; 111 if(low[temp][0]==low[y][0]||low[y][0]==temp)//选择最小值次小的那棵子树 112 ans2=low[y][1]; 113 else 114 ans2=low[y][0]; 115 } 116 } 117 if(ans1==inf||ans2==inf) 118 printf("no answers!\n"); 119 else 120 printf("%d %d\n",ans1,ans2); 121 } 122 printf("\n"); 123 } 124 return 0; 125 }