题意:给你一棵无根树,求以x为根节点时, y的最小儿子和最小子孙,无儿子,输出no answer
思路:以1为跟DFS整棵树,记录以每个节点为跟的子树的最小儿子和次小儿子min_son[2],最小子孙min_down[N]
然后分情况讨论即可
感谢http://blog.youkuaiyun.com/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;
}