[HDU 5444]Elven Postman[nlogn建树][BST]

这篇博客介绍了如何利用二叉搜索树(BST)解决HDU 5444题目的邮递员路径问题。在建树过程中,同时记录路径。通过比较房间大小,决定新房间的位置,最终实现nlogn的时间复杂度解决问题。
摘要由CSDN通过智能技术生成

题目链接:[HDU 5444]Elven Postman[nlogn建树]

题意分析:

邮递员要给住在树上的房间送信,房间的安排规律是小的在东,大的在西,查询房间,输出邮递员要走的路径。

解题思路:

根据房间分布规则,在建树的同时把到达这房间的路径记录下来。

这里用了set来建树,初始时放入根结点。根据房间分布规则,如果查询到的房间都不在set中,说明是目前房间都大的,那么把它加入到当前最大房间的西边;如果查询到的房间在set中,那么分为两种情况:第一种:这个房间的东边没有房间,那么直接把新房间安排到东边;第二种:有房间了,那么就找比这个房间次小的那个房间,把新房间放到这个房间的西边去。

对第二种情况这么做的理由解释下:首先,如果次小房间的左边有房间了,那么说明有个比次小房间大的房间,但是之前说过,此时的新房间应该满足:这个房间 > 新房间 > 次小房间,如果左边还有,那么说明这个次小房间绝对不是次小房间,就矛盾了。在这里,是不会发生"次小房间"的左边是"这个房间"的,因为"这个房间"的右边已经有房间了,如果右边的房间比"次小房间"小,那么它应该在"次小房间"的右边,如果比"次小房间"大,那么它才是次小房间。

至此,证毕。

个人感受:

nlogn建树,咔咔,感谢队里的小伙伴提供的思路和帮我debug。

具体代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;

const int MAXN = 1e3 + 111;

int l[MAXN], r[MAXN];  // l:结点i的左结点 r:结点i的右结点

int main()
{
    int t, n, m, x; scanf("%d", &t);
    while (t --)
    {
        scanf("%d", &n);
        string ans[MAXN];
        set<int> s;
        memset(l, 0, sizeof l);
        memset(r, 0, sizeof r);
        for (int i = 0; i < n; ++i)
        {
            scanf("%d", &x);
            if (i == 0) s.insert(x);
            else
            {
                set<int>::iterator it = s.upper_bound(x);
                if (it == s.end()) // 比所有结点都大,直接放到树的最左边
                {
                    --it;
                    l[*it] = x;
                    ans[x] = ans[*it] + "W";
                }
                else
                {
                    if (!r[*it]) // 如果右结点空缺,直接放到右边
                    {
                        r[*it] = x;
                        ans[x] = ans[*it] + "E";
                    }
                    else // 否则放到次小结点的左边
                    {
                        --it;
                        l[*it] = x;
                        ans[x] = ans[*it] + "W";
                    }
                }
                s.insert(x);
            }
        }
        scanf("%d", &m);
        for (int i = 0; i < m; ++i)
        {
            scanf("%d", &x);
            cout << ans[x] << '\n';
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值