题目大意:给定一个二维网图,里面有很多颗星星,每一颗星星都有他自己的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.