线段树题。题意:大学门口有一个巨大的矩形布告板,高度为h,宽度为w。这个广告牌会被贴上许多高度为1宽度未知的公告,为了使公告尽可能的被更多人看到,所以公告会被贴得尽量高并且总是选择最靠左边的位置。假设布告板的高度从高到低编号为1~h,现在有n个公告要贴,告诉你每一个公告的宽度,如果这个公告能被贴在布告板上,输出它的高度编号,否则输出-1。
我的解题思路:注意到h与w的范围可以达到10的9次方,如果以h的范围来建树应该会爆内存。但是n的最大值不过是20万而已,分析一下可知n个公告最多占用布告板的高度为n。所以应该可以用n的范围来开内存,然后以min(n, h)的值作为区间范围来建树。节点存储高度编号区间的剩余可用宽度最大值就可以了。
我的解题代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 200002
#define LL(x) (x << 1)
#define RR(x) (x << 1 | 1)
struct ST
{
int left, right, mid;
int maxvalue; //最大剩余空间
void init()
{
mid = (left + right) >> 1;
}
};
ST node[N<<2];
int h, w, n;
int m;
void BuildTree(int left, int right, int x);
int Update(int a, int x);
void PushUp(int x);
int main()
{
int a;
while (~scanf("%d %d %d", &h, &w, &n))
{
m = h > n ? n : h; //判断建树区间
BuildTree(1, m, 1);
while (n--)
{
scanf("%d", &a);
if (node[1].maxvalue < a)
{
puts("-1");
continue;
}
printf("%d\n", Update(a, 1));
}
}
return 0;
}
void BuildTree(int left, int right, int x)
{
node[x].left = left;
node[x].right = right;
node[x].maxvalue = w;
node[x].init();
if (left == right) return;
BuildTree(left, node[x].mid, LL(x));
BuildTree(node[x].mid + 1, right, RR(x));
return;
}
int Update(int a, int x)
{
while (node[x].left != node[x].right)
{
x = node[LL(x)].maxvalue >= a ? LL(x) : RR(x); //优先贴左边
}
node[x].maxvalue -= a;
PushUp(x);
return node[x].mid;
}
void PushUp(int x)
{
while (x != 0)
{
x >>= 1;
node[x].maxvalue = max(node[LL(x)].maxvalue, node[RR(x)].maxvalue);
}
return;
}