题目在此:传送门
题意:在一个坐标轴上,有n颗星星,每颗星都有等级,等级的范围为0~n-1,每颗星的等级为它左下角存在的星星(不包括自身,y坐标可以相等)的数量,有几颗星等级就为几,然后依次输出等级0~n-1的星的数量;
思路:线段树,因为是要判断左下角星星的数量,那么我们先以y坐标升序排序,如果y坐标相同就以x坐标升序排序,这样就能保证我们判断一个星星的等级时,它左下角的所有点都已经放入线段树中;排序题目已经帮助我们完成,那么就是线段树该如何存点。线段树只用来存每颗星星的x坐标,因为y是升序的关系,我们能保证区间查询某个星星时所有的点都在该星星下方,这时我们只需要判断x坐标是否比查询的星星的x坐标小就可以了;
附上代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<vector>
#include<cstdio>
#include<set>
#define MAXN 15005
#define maxn 32005//坐标的最大值
#define INF 1000000007
#define lmid l,m,rt<<1
#define rmid m+1,r,rt<<1|1
using namespace std;
int tree[maxn<<2];
struct node
{
int x,y;
int dj;//每颗星星的等级
}s[MAXN];
int ans[MAXN];//每个等级星星的数量
void pushup(int rt)
{
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt]=0;
return ;
}
int m=(l+r)>>1;
build(lmid);
build(rmid);
pushup(rt);
}
void update(int L,int C,int l,int r,int rt)
{
if(l==r)
{
tree[rt]+=C;//个数加1
return ;
}
int m=(l+r)>>1;
if(L<=m) update(L,C,lmid);
else update(L,C,rmid);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(l>=L&&R>=r)
{
return tree[rt];
}
int m=(l+r)>>1;
int res=0;
if(m>=L) res+=query(L,R,lmid);
if(R>m) res+=query(L,R,rmid);
return res;
}
int main()
{
memset(ans,0,sizeof(ans));
int n;
scanf("%d",&n);
int m=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&s[i].x,&s[i].y);
s[i].dj=0;
m=max(m,s[i].x);
}
build(0,m,1);
for(int i=0;i<n;i++)
{
if(i&&s[i].x==s[i-1].x&&s[i].y==s[i-1].y)
{
s[i].dj=s[i-1].dj;
ans[s[i].dj]++;
}
else {
s[i].dj=query(0,s[i].x,0,m,1);
ans[s[i].dj]++;
}
update(s[i].x,1,0,m,1);
}
for(int i=0;i<n;i++)
cout<<ans[i]<<endl;
return 0;
}
有到题与此题类似,可做练习题传送门;