题意:给你一棵无根树,求以x为根节点时, y的最小儿子和最小子孙,无儿子,输出no answer
思路:以1为跟DFS整棵树,记录以每个节点为跟的子树的最小儿子和次小儿子min_son[2],最小子孙min_down[N]
然后分情况讨论即可
感谢http://blog.csdn.net/hqd_acm/article/details/6750163 的题解
/* 首先以1为根,扫描一遍树,得到每个节点的minchild[i][2],儿子节点的最小值和次小值(不同子树的) 和每个节点的最小后缀的值mindown[i] (1)如果x是y的父节点的话,那么直接输出mindown[i],minchild[i][0]即可 (2)如果y是x的父节点 【1】当y不为1的时候 对于第一问 找到y到x这条路径上离y最近的节点z,若z=minchild[0],输出minchild[1]和y的父亲节点的最小值, 否则输出minchild[0]和y的父亲节点的最小值 对于第二问 输出1 【2】当y是1的时候(预先处理出他的最小和次小的后缀值mindown[0],mindown[1]) 对于第一问 找到y到x这条路径上离y最近的节点z,若z=minchild[0],输出minchild[1],否则输出minchild[0] 对于第二问 找到y到x这条路径上离y最近的节点z的最小后缀值(包括z),和mindown[0]比较, 不同输出mindown[1],否则输出mindown[0] */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #define inf (1 << 30) #define mod 1000000007 #define N 100005 const double eps = 1e-12; const double pi = acos(-1.0); using namespace std; struct NODE { int u, v; int next; }; int T, n, m, e, tim; int head[N], s_in[N], s_out[N], min_son[N][2], min_down[N], min_down1[2], f[N]; NODE edge[N * 2]; int init() { e = tim = 0; memset(head, -1, sizeof(head)); return 1; } int add_edge(int u, int v) { edge[e].u = u; edge[e].v = v; edge[e].next = head[u]; head[u] = e++; return 1; } int get_two(int *s, int x) { if(x < s[0]) { s[1] = s[0]; s[0] = x; } else if(x < s[1]) s[1] = x; return 1; } int DFS(int t, int p) { int i, v; min_son[t][0] = min_son[t][1] = min_down[t] = n + 1; s_in[t] = s_out[t] = ++tim; f[t] = p; for (i = head[t]; i != -1; i = edge[i].next) { v = edge[i].v; if (v == p) continue; get_two(min_son[t], v); DFS(v, t); s_out[t] = ++tim; min_down[t] = min(min_down[t], min_down[v]); } min_down[t] = min(min_down[t], min_son[t][0]); return 1; } int find(int x, int y) { if (f[x] == y) return x; return find(f[x], y); } int main() { int i, j, x, y, z, zz, ans1, ans2, v; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); init(); for (i = 1; i < n; i++) { scanf("%d%d", &x, &y); add_edge(x, y), add_edge(y, x); } DFS(1, n + 1); min_down1[0] = min_down[1], min_down1[1] = n + 1; for (i = head[1]; i != -1; i = edge[i].next) { v = edge[i].v; v = min(v, min_down[v]); if (v == min_down1[0]) continue; min_down1[1] = min(min_down1[1], v); } for (i = 1; i <= m; i++) { scanf("%d%d", &x, &y); if (s_in[y] > s_in[x] || s_out[y] < s_in[x] || s_out[x] < s_in[y]) ans1 = min_son[y][0], ans2 = min_down[y]; else { z = find(x, y); if (z == min_son[y][0]) ans1 = min(f[y], min_son[y][1]); else ans1 = min(f[y], min_son[y][0]); if (y != 1) ans2 = 1; else { zz = min(z, min_down[z]); if (zz == min_down1[0]) ans2 = min_down1[1]; else ans2 = min_down1[0]; } } if (ans1 == n + 1) printf("no answers!\n"); else printf("%d %d\n", ans1, ans2); } printf("\n"); } system("pause"); return 0; }