POJ 2352 Stars 线段树 pascal

题目大意:给定一个二维网图,里面有很多颗星星,每一颗星星都有他自己的level,对于每一颗,他的level是在他左下方的星星个数(允许是边界。其实换句话来说就是在原点到这个点的坐标内的除他本身所有点的个数),最后求出每个level(0~n-1)的个数各有多少个

题目分析:由题可得,level[x]的个数其实就是他左下方星星的个数,那么由于y值是递增的,所以出现一种很微妙的关系:我们在建好树之后去计算星星的数量时等于从低到高开始找,那么也就意味着说即使x值在存储中多次出现,但他的所包含的星星的数量由于前面的更新而发生了改变,所包含的数量会增加。所以我们只需要存储其很坐标的值就可以了,然后对于x建树,每计算完一个星星之后把这个星星所被被包含树的节点的w增加。如果说读入时y的大小不是递增的话还要加一个排序,以y的大小为核心去改变每个x的位置。

代码:

type
  rec=record
        l,r,w:longint;
      end;
var
  tree:array[0..32000*4] of rec;    //树
  ans:array[0..32000] of longint;   //计算   
  a:array[1..15000] of longint;     //存储x
  b,i,max,n:longint;
  procedure build(l,r,i:longint);
  var
    mid:longint;
  begin
    tree[i].l:=l;
    tree[i].r:=r;
    tree[i].w:=0;
    if l=r then exit;
    mid:=(tree[i].l+tree[i].r) div 2;
    build(l,mid,i*2);
    build(mid+1,r,i*2+1);
  end;
  function find(l,r,i:longint):longint;
  var
    mid,sum:longint;
  begin
    if (tree[i].l=l) and (tree[i].r=r) then exit(tree[i].w)
    else
      begin
        mid:=(tree[i].l+tree[i].r) div 2; sum:=0;
        if l>mid then sum:=sum+find(l,r,i*2+1)
        else
          if r<=mid then sum:=sum+find(l,r,i*2)
          else
            sum:=sum+find(l,mid,i*2)+find(mid+1,r,i*2+1);
        exit(sum);
      end;
  end;
  procedure insert(x,i:longint);
  var
    mid:longint;
  begin
    inc(tree[i].w);
    if (tree[i].l=tree[i].r) and (tree[i].r=x) then exit;
    mid:=(tree[i].l+tree[i].r) div 2;
    if x<=mid then insert(x,i*2)
    else
      insert(x,i*2+1);
  end;
begin
  readln(n); max:=0;
  fillchar(ans,sizeof(ans),0);
  for i:=1 to n do
  begin
    readln(a[i],b);
    if a[i]>max then max:=a[i];        //求出x的最大值
  end;
  build(0,max,1);       //建树
  for i:=1 to n do
  begin
    inc(ans[find(0,a[i],1)]);       //计算个数(会重复做一个点,原因看分析)
    insert(a[i],1);                 //更新
  end;
  for i:=0 to n-1 do writeln(ans[i]);
end.



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值