题目大意:

给你一个二维的坐标系(32000*32000),里面有n(15000)个点,告诉你每个点的坐标(各个点各不相同)。定义: (x0,y0) 的左下角区域为:{ (x,y) | 0<=x<=x0 && 0<=y<=y0 };让你输出左下角区域有分别有0个点,1个点。。。n-1个点的点的个数。
注:坐标点以y轴坐标的升序给出,y坐标相同的点以x轴坐标的升序给出。

分析:

这个题一开始想要用二维树状数组来做,但是觉得太麻烦了,去网上看了一下别人的思路,发现了一个很巧妙的地方。因为输入的时候是按照一定的升序顺序输入的,也就是一行一行输入,那么,其实,这些星星在一行上也是一样的(假设这些星星可以重合)。也就是说,在y=0的时候,输入一个点的坐标,那这个星星的左面有多少个点是已经算出来了的,用树状数组只需要log32000的时间。然后就是关键了,到了输入y=1行的点的坐标的时候,直接还是把它记录到y=0的那一行上面去,然后再用树状数组来求出该点的level值,时间复杂度还是log32000。综合时间复杂度为15000*log32000;

代码:

#include<iostream>
#include<stdio.h>
#include<string.h>

using namespace std;

int tree[40000]={0};
int num[40000]={0};
int n;

int lowbit(int x)
{
    return (-x)&x;
}

void add(int x,int t)
{
    while(x<=32010)
    {
        tree[x]+=t;
        x=x+lowbit(x);
    }
}

int sum(int x)
{
    int s=0;
    while(x>0)
    {
        s+=tree[x];
        x=x-lowbit(x);
    }
    return s;
}

int main()
{
    while(cin>>n)
    {
        memset(tree,0,sizeof(tree));
        memset(num,0,sizeof(num));
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            x++;
            num[sum(x)]++;
            //cout<<sum(x)<<endl;
            add(x,1);
        }
        for(int i=0;i<n;i++)
        {
            cout<<num[i]<<endl;
        }
    }
}

后注:

注意坐标范围是[0,32000],但是树状数组里不能有0,所以把x整体加1。