hdu 4008 树形dp

思路:我们定义一个dfn[i],Maxndfn[i]来确定节点i的访问次序,以及其子节点的最大访问次序。那么另一个节点是其子树的节点当且仅当dfn[j]>=dfn[i]&&dfn[j]<=Maxdfn[i];

这是就可以先以1为根,dfs找出所有节点最小儿子,次小儿子,以及最小子孙,次小子孙。

剩下就可以分情况:

对于x,y:

1.若与y相连的边数为1,那么一定就是no answers!。

2.对于最小儿子节点的询问:

(1)若x是y的子节点,那么如果x包含在y的最小儿子子树中,那么就答案就是次小儿子与其父节点中较小的,否则就是最小儿子与其父节点中较小的。

(2)若y是x点子节点(设不是y的子节点的都是其根节点),那么就直接输出最小儿子。

3.对于最小子孙节点的询问:

(1)若x是y的子节点,那么如果x包含在y的最小子孙所在子树中(小于以y为根的子树),那么就答案就是次小子孙,否则就是最小子孙,其实这只设和y为1的情况,若y为其它节点,其最小子孙直接就是1。

(2)若y是x点子节点(设不是y的子节点的都是其根节点),那么就直接输出最小子孙。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#define Maxn 100010
#define inf 0x7fffffff
using namespace std;
int son[Maxn],nson[Maxn],der[Maxn],nder[Maxn],n,q,dfn[Maxn],Maxdfn[Maxn],lab,dp[Maxn],road[Maxn],father[Maxn];
vector<int> head[Maxn];
void init()
{
    int i;
    memset(son,0,sizeof(son));
    memset(nson,0,sizeof(nson));
    memset(der,0,sizeof(der));
    memset(nder,0,sizeof(nder));
    memset(dfn,0,sizeof(dfn));
    memset(father,0,sizeof(father));
    memset(dp,0,sizeof(dp));
    memset(road,0,sizeof(road));
    memset(Maxdfn,0,sizeof(Maxdfn));
    lab=0;
    for(i=0;i<=n;i++)
        head[i].clear();
}
void add(int u,int v)
{
    head[u].push_back(v);
    head[v].push_back(u);
}
void dfs(int u,int f)
{
    int i,v,si;
    dfn[u]=Maxdfn[u]=++lab;
    dp[u]=u;
    son[u]=nson[u]=der[u]=nder[u]=inf;
    si=head[u].size();
    for(i=0;i<si;i++)
    {
        v=head[u][i];
        if(v==f)
            continue;
        dfs(v,u);
        dp[u]=min(dp[u],dp[v]);
        Maxdfn[u]=max(Maxdfn[u],Maxdfn[v]);
        if(v<son[u])
        {
            nson[u]=son[u];
            son[u]=v;
        }
        else
        {
            if(v<nson[u])
                nson[u]=v;
        }
        if(der[u]>dp[v])
        {
            nder[u]=der[u];
            der[u]=dp[v];
            road[u]=v;
        }
        else
            if(nder[u]>dp[v]) nder[u]=dp[v];
    }
    father[u]=f;
}
int main()
{
    int i,j,a,b,t,x,y;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d%d",&n,&q);
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        dfs(1,1);
        for(i=1;i<=q;i++)
        {
            scanf("%d%d",&x,&y);
            int ans1,ans2;
            if(head[y].size()==1)
            {
                puts("no answers!");
                continue;
            }
            if(dfn[x]<dfn[y]||dfn[x]>Maxdfn[y])
                printf("%d %d
",son[y],der[y]);
            else
            {
                if(dfn[x]>=dfn[son[y]]&&dfn[x]<=Maxdfn[son[y]])
                    ans1=nson[y];
                else
                    ans1=son[y];
                if(dfn[x]>=dfn[road[y]]&&dfn[x]<=Maxdfn[road[y]])
                    ans2=nder[y];
                else
                    ans2=der[y];
                if(y!=1) ans1=min(ans1,father[y]),ans2=1;
                printf("%d %d
",ans1,ans2);
            }
        }
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wangfang20/p/3243540.html