题意:给星星的坐标,定义每个星星左下角(包括正左边和正上方)的星星数是它的level,统计各个level的星星数。
分析:乍看是个二维的统计,因为数据给出的是 y坐标升序,y相等 x坐标升序,所以可以一次读入数据,只要统计 x左边的星星数就行了,
这道题很好的启示就是二维降一维的方法————按某种规则排序。
下面给出了线段树和树状数组的写法。
点线段树cpp代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
const int root = 0;
struct Node{
int l,r,cnt;
int lnd,rnd;
}node[60005];
int cnt,cntx;
int indx[15010];
int x[15010],y[15010];
void Creat(int p,int l,int r)
{
node[p].l = l; node[p].r = r;
node[p].cnt = 0;
if (l < r)
{
int mid = (l + r) >> 1;
node[p].lnd = ++cnt;
Creat(cnt,l,mid);
node[p].rnd = ++cnt;
Creat(cnt,mid+1,r);
}
else {node[p].lnd = node[p].rnd = -1;}
}
void upData(int p)
{
if (node[p].l < node[p].r)
node[p].cnt = node[node[p].lnd].cnt + node[node[p].rnd].cnt;
}
void Insert(int p,int id)
{
if (id == node[p].l && id == node[p].r)
node[p].cnt++;
else {
int mid = (node[p].l + node[p].r) >> 1;
if (mid < id)
Insert(node[p].rnd,id);
else Insert(node[p].lnd,id);
}
upData(p);
}
int query(int p,int l,int r)
{
int ans = 0;
if (l <= node[p].l && node[p].r <= r)
ans = node[p].cnt;
else{
int mid = (node[p].l + node[p].r) >> 1;
if (mid >= l)
ans += query(node[p].lnd,l,r);
if (mid < r)
ans += query(node[p].rnd,l,r);
}
return ans;
}
int Bi_Search(int key)
{
int l = 1,r = cntx+1,mid;
while (l < r)
{
mid = (l + r) >> 1;
if (indx[mid] == key)
return mid;
else if (indx[mid] < key)
l = mid + 1;
else r = mid;
}
}
void Init_Index()
{
sort(indx+1,indx+1+cntx);
// for (int i = 1; i <= cntx; i++)
// printf("%d,",indx[i]);
int m = 1;
for (int i = 2; i <= cntx; i++)
{
if (indx[i] != indx[i-1])
{
m++;
indx[m] = indx[i];
}
}
cntx = m;
}
int main()
{
int n,i,j,k,id;
int count[15010];
while (scanf("%d",&n) != EOF)
{
for (i = 1; i <= n; i++)
{
count[i] = 0;
scanf("%d %d",&x[i],&y[i]);
indx[i] = x[i];
}
// for (i = 1; i <= n ;i++)
// printf("%d ",indx[i]);
// printf("\n");
cntx = n;
Init_Index();
/* for (i = 1; i <= cntx; i++)
printf("%d ",indx[i]);
printf("cntx = %d\n",cntx);*/
cnt = 0;
Creat(root,1,cntx);
for (i = 1; i <= n; i++)
{
id = Bi_Search(x[i]);
// printf("id = %d\n",id);
k = query(root,1,id);
// printf("i = %d,k = %d\n",i,k);
count[k] ++;
Insert(root,id);
}
for (i = 0; i < n; i++)
printf("%d\n",count[i]);
}
return 0;
}
树状数组的cpp代码:
#include<stdio.h>
int a[32002];
int level[15000];
int N;
int lowbit(int n){
return n&(-n);
}
int Sum(int n)
{
int result = 0;
while(n!=0){
result+=a[n];
n-=lowbit(n);
}
return result;
}
void Update(int n)
{
while(n<=32001){
a[n]++;
n+=lowbit(n);
}
}
void init()
{
int i;
for(i=0;i<=N;i++)
level[i]=a[i]=0;
}
int main()
{
int x,y,i;
scanf("%d",&N);
i=N;
init();
while(i--){
scanf("%d %d",&x,&y);
level[Sum(x+1)]++;
Update(x+1);
}
for(i=0;i<N;i++)
printf("%d\n",level[i]);
}