题目大意:在h*w 高乘宽这样大小的 board上要贴广告,每个广告的高均为1,wi值就是数据另给,每组数组给了一个board和多个广告,要你求出,每个广告应该贴在board的哪一行,如果实在贴不上,就输出-1;
这个题目也难以想到居然是用线段树来做
我们需要考虑的是,线段树究竟表示的是什么数据。在这个题目里,由于每个广告的高都为1,是不是好像感觉每一行都是一个叶子节点一样。没错,就是这样。。。化抽象为具体一点,那就是把这个board给竖起来,这样最底部的孩子存贮了当前行的空闲宽度,每个父节点都是左右孩子的max。
其实思路这样理一下,感觉其实很简单,是把。
还要注意的一点是,虽然题目说h 和 w高达10的九次方,但并不意味着我线段树要建如此大(事实上真要建也建不了),由于广告最多只有200000个,所以,你想,底层叶子最多,也就每个广告占一行,那也就是这么大。。。因此线段树的大小真心不能只看表面
#include <iostream> #include <cstdio> #include <cstring> #define Lson (x<<1),l,mid #define Rson (x<<1|1),mid+1,r #define maxn 200005 using namespace std; int d[maxn*4]; int max(int a,int b) { return a>b ? a:b; } void getup(int x) { d[x]=max(d[x<<1],d[x<<1|1]); } void build (int wid,int x,int l,int r) { if (l==r){d[x]=wid;return;} int mid=(l+r)/2; build(wid,Lson); build(wid,Rson); getup(x); } /*void update(int a,int x,int l,int r) { if (l==r) { d[x]-=a; } int mid=(l+r)/2; if (a<=d[x<<1]) update(a,Lson); else update(a,Rson); getup(x); }*/ int query(int a,int x,int l,int r) { if (l==r) { if (d[x]<a) return -1;//此时根本就贴不上 else {d[x]-=a;return l;} } int mid=(l+r)/2; int ret=0; if (a<=d[x<<1]) ret=query(a,Lson); else ret=query(a,Rson); if (ret>0) getup(x);//及时更新父节点 return ret; } int main() { int h,wid,q; while (scanf("%d %d %d",&h,&wid,&q)!=EOF) { if (h>q) h=q;//注意h过大的时候,以广告数q为宗旨。 build(wid,1,1,h); int i,j; for (i=1;i<=q;i++) { int a; scanf("%d",&a); int ans=query(a,1,1,h); printf("%d ",ans); //if (ans!=-1) //update(a,1,1,h); } } return 0; }