hdu 2795 Billboard 线段树

题目大意:给一个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.


你可能感兴趣的:(hdu 2795 Billboard 线段树)