题意:统计几级星的个数,对每个星星来说,有多少x,y都不超过他的星星,他就是几级星(不包括自身);
题目给的星星是按y升序,y相等的时候x升序给出的,所以只需要知道每个星星前面有多少个x不超过他的就行;
很容易想到O(n2)的算法,但时间复杂度太高;
这里用线段树或者树状数组,每次输入一次查询一次x,在更新一次x;
用v表示结果,用t表示每个区间每个区间有多少个x的坐标;
线段树:
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=32000+10;//x,y的最大值
int t[maxn<<2],v[maxn];
int ans,n,x,y;
void query(int l,int r,int rt){//查询x前面有多少个星星
if(x>=r) ans += t[rt];
else if(x<l) return;
else{
int mid = (l+r)>>1;
query(l,mid,rt<<1);
query(mid+1,r,rt<<1|1);
}
}
void update(int l,int r,int rt){//更新x所在的所有区间,l=r的时候是找到了子节点
if(l==r){
t[rt]++;
return;
}
int mid = (l+r)>>1;
if(x<=mid) update(l,mid,rt<<1);
else update(mid+1,r,rt<<1|1);
t[rt]++;
}
int main()
{
cin>>n;
for(int i = 0;i < n;i++){
cin>>x>>y;//输入一个操作一次
ans = 0;//ans是记录前面有多少星
query(0,maxn,1);
v[ans]++;
update(0,maxn,1);
}
for(int i = 0;i < n;i++)
cout<<v[i]<<endl;
return 0;
}
树状数组:
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=32000+10;
int t[maxn],v[maxn];
int ans,n,x,y;
int lowbit(int x){//查找最低位的1
return x&(-x);
}
int query(int x){//查询前x的和
int ans = 0;//ans是结果
while(x>0){//直到x减到0为止
ans += t[x];//ans每次加上当前的值
x -= lowbit(x);//x减去当前最低位的1
}
return ans;
}
void update(int x){//更新x的值
while(x<=maxn){直到x增加到最大值
t[x]++;//当前区间加一
x += lowbit(x);//加上最低位的1
}
return;
}
int main()
{
cin>>n;
for(int i = 0;i < n;i++){
cin>>x>>y;
x++;//防止x是0时的陷阱,最后统计每个级别的星的数量,不会影响那个结果
v[query(x)]++;
update(x);
}
for(int i = 0;i < n;i++)
cout<<v[i]<<endl;
return 0;
}