题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795
题目大意:有一个h*w的公告牌,要在其上贴公告。现在有n个公告,每个公告的尺寸为1*wi,即高度都为1,现在依次给出n个公告的宽度wi,需要求出每个公告在广告牌所在的行数。要求:对于同一个公告尽量贴在公告牌的上方,如果高度一致,尽量贴在广告牌的左侧。如果没有合适的位置,则输出-1.
例:
Sample Input
3 5 5
2
4
3
3
3
Sample Output
1
2
1
3
-1
解题思路:这个题目和ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps很类似,可以使用同一种思想。这里我们用线段树节点存储该区间内空位最大的那一行的空位长度,只要维护每个区间的最大值就可以了。然后每输入一个公告的宽度,先与树的根相比较,如果宽度大于树的根,肯定无法插入进去,所以直接输出-1,否则的话,就先与左子树相 比较,如果比它大,就查询左子树,否则查询右子树,查询之后再减去相应的长度即可。
然后这题有点要注意的是,树的叶子节点总个数应该是h个,然而如果h>n的话,叶子的个数应该为n个,因为多余的无意义了。
附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define maxn 200005
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define pushup() tree[root]=max(tree[root<<1],tree[root<<1|1])
int tree[maxn<<];
int n,h,w,x; void build(int l,int r,int root)
{
if(l==r)
{
tree[root]=w;
return;
}
int mid=l+r>>;
build(lson);
build(rson);
pushup();
}
int query(int val,int l,int r,int root)
{
if(l==r)
{
tree[root]-=val;
return l;
}
int mid=l+r>>;
int ans;
if(val<=tree[root])
{
if(tree[root<<]>=val)
ans=query(val,lson);
else
ans=query(val,rson);
}
pushup();
return ans;
} int main()
{
while(~scanf("%d%d%d",&h,&w,&n))
{
if(h>n)
h=n;
build(,h,);
for(int i=;i<=n;i++)
{
scanf("%d",&x);
if(x>tree[])
printf ("%d\n",-);
else
printf("%d\n",query(x,,h,));
}
}
return ;
}