题目大意:给一个h*w的公告牌,h是高度,w是宽度,一个单位高度为一行,然后会有一些公告贴上去,公告是1*wi大小的长纸条,优先贴在最上面并且最左边的位置,如果没有空间贴的下,就输出-1,如果可以,就输出所贴的位置(第几行)。
分析:给我感觉这题是比较高层次的线段树的应用,因为我是看了题解才想到的(也可能是我比较水)。要想知道公告贴哪里,首先得知道有没有位置贴公告吧,所以就用线段树节点区间【a,b】表示第a行到第b行中最大的空位,叶节点区间【x,x】表示该行剩下多少个位置。若放不下则返回-1,否则的话就继续往下找(优先找左节点),一直找到叶节点并更新叶节点以及它父节点的权值就好了。
下面附程序:
var h,w,n,i,x:longint; t:array[1..600000,1..3] of longint; function max(x,y:longint):longint; begin if x>y then exit(x) else exit(y); end; procedure hehe(d,l,r:longint); var m:longint; begin t[d,1]:=l; t[d,2]:=r; t[d,3]:=w; if l=r then exit; m:=(l+r) div 2; hehe(d*2,l,m); hehe(d*2+1,m+1,r); end; function work(d,x:longint):longint; begin if t[d,3]<x then exit(-1); if t[d,1]=t[d,2] then begin t[d,3]:=t[d,3]-x; exit(t[d,1]); end; if t[d*2,3]>=x then work:=work(d*2,x) else work:=work(d*2+1,x); t[d,3]:=max(t[d*2,3],t[d*2+1,3]); end; function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end; begin while not eof do begin readln(h,w,n); hehe(1,1,min(n,h)); for i:=1 to n do begin readln(x); writeln(work(1,x)); end; end; end.