题目链接:[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;
}