hdu4008 DFS

题意:给你一棵无根树,求以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;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值