HDU-4008-treeDP

这题看好多天了。为什么看那么久呢?因为对于我来说有点难,难了就不能静心了,一会看人人一会聊天的。

又不想看别人的思路。

今天终于静下心来想了。我想的和网上baidu google 到的都不太一样。

上代码 。


int son1[N], son2[N], fa[N]; //向下最大 向下次大 向上最大 儿子
int dw1[N], dw2[N], up[N]; //向下最大 向下次大 向上最大 子孙
int ds1[N], ds2[N]; // 最(次)小子孙方向的儿子
int st[N], ed[N]; //时间戳 用于判断是否是 直系祖宗和子孙的关系
vector<int>v[N];
int n, q, cnt;

void dfs1(int s, int pre) //处理向下的
{
    dw1[s] = dw2[s] = son1[s] = son2[s] = inf;
    ds1[s] = ds2[s] = inf;
    st[s] = ++cnt;
    int ss, i, len = v[s].size();;
    for(i=0; i<len; i++)
    {
        ss = v[s][i];
        if(ss==pre) continue;
        dfs1(ss, s);

        if(ss<son1[s])
        {
            son2[s] = son1[s];
            son1[s] = ss;
        }
        else son2[s] = min(son2[s], ss);

        int dw = min(dw1[ss], ss);
        if(dw<dw1[s])
        {
            dw2[s] = dw1[s];
            dw1[s] = dw;
            ds2[s] = ds2[s];
            ds1[s] = ss;
        }
        else if(dw<dw2[s])
        {
            dw2[s] = min(dw2[s], dw);
            ds2[s] = ss;
        }
    }
    ed[s] = cnt;
}

void dfs2(int s, int pre) //处理向上的
{
    fa[s] = pre;
    if(s==1) up[1] = fa[1] = inf;
    else if(dw1[pre]==dw1[s] || dw1[pre]==s) up[s] = min( pre, min(dw2[pre], up[pre]) );
    else up[s] = min( pre, min( dw1[pre], up[pre] ) );

    int i, ss, len = v[s].size();
    for(i=0; i<len; i++)
    {
        ss = v[s][i];
        if(ss==pre) continue;
        dfs2(ss, s);
    }
}

inline bool ispre(int a, int b) //判断a是b的祖宗否
{
    if(st[a]<st[b] && ed[a]>=ed[b]) return true;
    else return false;
}

void in(int &a) //写挫的代码一直TLE , 其实是因为算法不对
{
    char ch;
    while(ch=getchar(), ch<'0'||ch>'9');
    a = ch-'0';
    while(ch=getchar(), ch>='0'&&ch<='9') a = a*10+ch-'0';
}

int main()
{
    int t, i, a, b;
    in(t);
    while(t--)
    {
        in(n);in(q);
        for(i=1; i<=n; i++) v[i].clear();
        for(i=1; i<n; i++)
        {
            in(a);in(b);
            v[a].push_back(b);
            v[b].push_back(a);
        }
        cnt = 0;
        dfs1(1, 0);
        dfs2(1, 0);
        while(q--)
        {
            in(a);in(b);
            if(v[b].size()==1) puts("no answers!");
            else if( ispre(b, a) ) //如果b是a的祖宗
            {
                int a1, a2;
                if( son1[b] == a || ispre(son1[b], a) ) a1 = min(fa[b], son2[b]);
                else a1 = min(fa[b], son1[b]);
                if( ds1[b] == a || ispre(ds1[b], a) || ispre(a, ds1[b]) ) a2 = min(up[b], dw2[b]);
                else a2 = min(up[b], dw1[b]);
                printf("%d %d\n", a1, a2);
            }
            else  printf("%d %d\n", son1[b], dw1[b]); //否则就是预处理的
        }
        puts("");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值