第一眼看去这道题还真没看出来是线段树的题,可能是题目做的少吧。
题意:给你一个h*w大的墙,让你贴n张海报,每张海报规格是1*wi。尽可能的忘左上方贴,(上优先于左)
输出每张海报的行数,贴不下的输出-1
(1 <= h,w <= 10^9; 1 <= n <= 200,000) //因为最多n张海报,所以h的范围实际上是1~200,000
线段树的叶子存的h行位置,每个阶段存的是在该区间内有没有合适的位置。
0.0好像很难懂的样子,算了,还是在代码里注释清楚吧,上代码:
#include <stdio.h>
#include <iostream>
#define MAX 20000005
using namespace std;
struct ac
{
int space; //存的是在l~r区间内,剩余空间的最大值,初始为w
int l,r;
}post[MAX];
int h,w,n;
inline int fmax(int a,int b)
{
return a>b?a:b;
}
void build(int l,int r,int k) //标准的建树
{
post[k].l=l;
post[k].r=r;
post[k].space=w;
if(l==r)
return ;
int mid=(l+r)/2;
build(l,mid,2*k);
build(mid+1,r,2*k+1);
}
void insert(int x,int k)
{
if(post[k].l==post[k].r) //当遍历到叶子的时候
{
if(post[k].space>=x) //如果剩余空间足够
{
post[k].space-=x; //贴上海报,空间-x
printf("%d\n",post[k].l);
}
else
printf("-1\n");
return ;
}
if(post[2*k].space>=x) //如果左子节点的空间比x大
insert(x,2*k);
else
insert(x,2*k+1);
post[k].space=fmax(post[2*k].space,post[2*k+1].space); //更新子节点之后,更新当前节点space值
}
int main()
{
int i;
while(scanf("%d %d %d",&h,&w,&n)!=EOF)
{
if(h>n) // 这个地方得注意,因为最多n张海报,每张海报规格为1*wi
h=n;
build(1,h,1); //建树
while(n--) //10^5
{
int x;
scanf("%d",&x);
insert(x,1); //更新同时输出
}
}
return 0;
}
总之感觉很神奇,这都能用线段树做!!