poj2352

纪念树状数组初步(……);

这题已经给了y升序,y相同时x升序,(yeah)

所以容易想到O(n^2)的模拟算法;

其实分析一下就是对于当前xi,统计之前有多少个小于等于xi(因为已经保证了没有相同坐标的点)

初学者(比如我),一开始感觉和树状数组没毛关系,但是……

仔细想想发现,树状数组是修改和区间求值的,我们能不能将问题转化呢?

可以!这里用到类似计数排序的思想,a数组表示对x可能出现的范围内中每个数表示的次数;

则:对于当前xi,之前小于等于xi的个数就等于sigma(a[0]~a[x[i]])

这下子就变成树状数组拿手的区间求和了!

但注意细节,因为存在x=0,但构建树状数组下标是从1开始的

所以我们把所有x加1即可,不影响位置之间的关系。

 var x,y,ans,b:array[..] of longint;
    c:array[..] of longint;
    maxx,i,n:longint;
function lowbit(x:longint):longint;   //树状数组的核心
  begin
    lowbit:=x and -x;
  end;
function ask(x:longint):longint;     //区间求和
  begin
    ask:=;
    while x<> do
    begin
      ask:=ask+c[x];
      x:=x-lowbit(x);
    end;
  end;
procedure work(x:longint);          //更改单点时,注意把父亲节点也要更新
  begin
    while x<=maxx do
    begin
      inc(c[x]);
      x:=x+lowbit(x);
    end;
  end; begin
  readln(n);
  for i:= to n do
  begin
    readln(x[i],y[i]);
    inc(x[i]);
    if x[i]>maxx then maxx:=x[i];             //限定范围
  end;
  for i:= to n do
  begin
    b[i]:=ask(x[i]);
    work(x[i]);
  end;
  for i:= to n do
    inc(ans[b[i]]);
  for i:= to n- do
    writeln(ans[i]);
end.

相对于线段树,树状数组实现还是很简单的,时空复杂度也不错!

上一篇:Objective-C介绍


下一篇:centos 安装 和 linux 简单命令