目录
题目
- 1000ms
- 131072K
蒜厂有一个 h×w 的矩形公告板,其中 h 是高度,w 是宽度。
现在有若干张 1×Wi 的公告, Wi 是宽度,公告只能横着放,即高度为 1 的边垂直于水平面,且不能互相有重叠,每张公告都要求尽可能的放在最上面的合法的位置上。
若可以放置,输出每块可放置的位置的行号;若不存在,输出 −1。行号由上至下分别为 1,2,...,h。
输入格式
第一行三个整数 h,w,n (1≤h,w≤10^9;1≤n≤200,000) 。
接下来 n 行,每行一个整数 Wi(1≤Wi≤10^9) 。
输出格式
输出n 行,一行一个整数。
样例输入
3 5 524333样例输出
1213-1
题解:
知识点:
线段树
分析:
我们让线段树维护[x,y]行中每一行剩余宽度的最大的一个,注意h=min(h,n);,高度h最高不能超过n。故pushup函数为width[id]=max(width[id<<1],width[id<<1|1]);,LL width[4*N];//维护每行剩余宽度
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=6e5+5;
typedef long long LL;
LL h,w,n;
LL width[4*N];//维护每行剩余宽度
bool flag;//可不可行
inline void pushup(LL id){//核心
width[id]=max(width[id<<1],width[id<<1|1]);
}
void build(LL id,LL l,LL r){
if (l==r){
width[id]=w;
return;
}
LL mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}
void update(LL id,LL l,LL r,LL x){
if (l==r){
width[id]-=x;//剩余宽度要减少
flag=true;
printf("%lld\n",l);
return;
}
LL mid=(l+r)>>1;
if (width[id<<1]>=x){
update(id<<1,l,mid,x);
}
if (width[id<<1|1]>=x && !flag){//!flag是看左子树是否安放了海报
update(id<<1|1,mid+1,r,x);
}
pushup(id);
}
int main(){
scanf("%lld%lld%lld",&h,&w,&n);
h=min(h,n);
build(1,1,h);
while (n--){
LL wide;
scanf("%lld",&wide);
flag=false;
if (width[1]>=wide){//如果[1,h]行剩余最大宽度比wide大
update(1,1,h,min(wide,w));
}
if (!flag){
puts("-1");
}
}
return 0;
}