题意:有个公告板,大小为h*w,要贴n张公告,每个公告的长度是k,高度固定为1,公告放的要尽可能靠上并尽可能靠左,每给出一张公告,要求这个公告在满足要求的情况下放在了第几层。
Sample Input
3 5 5 2 4 3 3 3
Sample Output
1 2 1 3 -1
思路:每次找到最大值的位子,然后减去L
线段树功能:query:区间求最大值的位子(直接把update的操作在query里做了)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
int c[maxn<<2];
int h,w;
void build(int l,int r,int rt)
{
c[rt]=w;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
int query(int num,int l,int r,int rt)
{
if(l==r) {
c[rt]-=num;
return l;
}
int mid=(l+r)>>1;
int ans=0;
if(num<=c[rt<<1]) ans=max(ans,query(num,l,mid,rt<<1));
else ans=max(ans,query(num,mid+1,r,rt<<1|1));
c[rt]=max(c[rt<<1],c[rt<<1|1]);
return ans;
}
int main()
{
int n,num;
while(scanf("%d%d%d",&h,&w,&n)!=EOF) {
if(h>n) h=n;
build(1,h,1);
while(n--) {
scanf("%d",&num);
if(num>c[1]) printf("-1\n");
else printf("%d\n",query(num,1,h,1));
}
}
return 0;
}
线段树有点二分的思想,,,用线段树去维护查找,因为我们要去查找最上面的所能放下木板的广告位,于是就用线段树来维护,根节点就是最大的广告位,如果木板大于最大的广告位就不行了。当放入木板后,广告位的容量就要减少,就直接单点更新。。
线段树绝对的好题啊!!!!!要理解线段树后才能理解这题。mark
2016.3.8 复习线段树又重新敲了一遍
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 2e5 + 10;
int c[N<<2];
void build(int l,int r,int rt,int num)
{
if(l==r) {
c[rt]=num;
return;
}
int mid=(l+r)>>1;
if(l<=mid) build(l,mid,rt<<1,num);
if(r>mid) build(mid+1,r,rt<<1|1,num);
c[rt]=num;
}
int ask(int l,int r,int rt,int num)
{
int ans=-1;
if(c[rt]<num) return ans;
if(l==r && c[rt]>=num) {
c[rt]-=num;
return ans=l;
}
int mid = (l+r)>>1;
if(c[rt<<1]>=num) ans=ask(l,mid,rt<<1,num);
else if(c[rt<<1|1]>=num) ans=ask(mid+1,r,rt<<1|1,num);
c[rt]=max(c[rt<<1],c[rt<<1|1]);
return ans;
}
int main()
{
int h,w,q,i,j,n;
while(scanf("%d%d%d",&h,&w,&n)!=EOF) {
build(1,min(h,n),1,w);
for(i=1;i<=n;i++) {
scanf("%d",&q);
int t = ask(1,min(h,n),1,q);
if(t) printf("%d\n",t);
else printf("-1\n");
}
}
return 0;
}