pku2352: http://poj.org/problem?id=2352
题意:给出星星的坐标,问每一层次n有多少个星星:星星a的左边或下边共有x个星星,则a属于层次x,ans[x]++,求ans[0]~ans[n-1]
解法1:线段树:从给出的坐标的顺序可知后面的坐标不会影响的前面的坐标,所以可以边输入边计算。首先建树,再从点1开始往下搜,若所求点d在树的左子树,继续往下搜,若在树的右子树,加上左子树的数目(左子树的点都小于d),再搜右子树,遇到左端点a与右端点b相同的情况,此时a=b=d,更新点,加一。
code1:
#include<iostream>
#include<cstdio>
#include<cstdlib>
struct abc
{
int l,r,cnt;
}v[33000*4];
int ans[16000];
void build(int s,int t,int k) //建树
{
v[k].l=s;
v[k].r=t;
v[k].cnt=0;
if(s==t)
return;
int mid=(s+t)/2;
build(s,mid,k*2);
build(mid+1,t,k*2+1);
}
int solve(int d,int k)
{
if(v[k].l==v[k].r) //l=r=d
return ++v[k].cnt; //更新点
else
{
int x=0;
if(d<=v[k*2].r)
x=solve(d,k*2);
else
x=v[k*2].cnt+solve(d,k*2+1);
v[k].cnt=v[k*2].cnt+v[k*2+1].cnt; //点往上更新
return x; //返回所求点左下点以及本身点的个数
}
}
int main()
{
int n,x,y;
while(scanf("%d",&n)!=EOF)
{
memset(ans,0,sizeof(ans));
build(0,32000,1);
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
ans[solve(x,1)-1]++;
}
for(int i=0;i<n;i++)
printf("%d\n",ans[i]);
}
}
/*input:
5
1 1
5 1
7 1
3 3
5 5
output:
1
2
1
1
0*/
解法2:树状数组:对于节点i,其父节点为i+i&(-i),其前一棵树为i-i&(-i),先初始化每个点为0,再求前x项和即可
code2:
#include<iostream>
#include<cstdio>
#include<cstdlib>
int ans[32010],v[32010];
int lowbit(int x) //求最小幂2^k
{
return x&(-x);
}
int sum(int x) //求前n项和
{
int s=0;
while(x>0)
{
s=s+v[x];
x=x-lowbit(x);
}
return s;
}
void update(int x) //对某个元素进行加法操作
{
while(x<32010)
{
v[x]++;
x=x+lowbit(x);
}
}
int main()
{
int n,x,y;
while(scanf("%d",&n)!=EOF)
{
memset(ans,0,sizeof(ans));
memset(v,0,sizeof(v));
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
ans[sum(x+1)]++; //树状数组是从1开始的
update(x+1);
}
for(int i=0;i<n;i++)
printf("%d\n",ans[i]);
}
}
/*input:
5
1 1
5 1
7 1
3 3
5 5
output:
1
2
1
1
0*/