视频解析:AcWing 1265. 数星星(每日一题)_哔哩哔哩_bilibili
思想
假设当前坐标是[x,y],那么题意就是求小于等于x的星星有多少个,下图中x就有4个星星,x自身的星星需要抛除掉。
那么这道题就转换为了求<=x的区间的星星的个数。
求某个区间个数可以转化为区间和,每个位置如果有星星就是1,没有就是0,最后对该区间求一个前缀和就求出了该区间的星星个数。
那么现在我们就有两个点需要计算:
1、求区间前缀和
2,修改区间内某个点的值(是星星就是1,不是就是0)
可以满足需求的数据结构有:树状数组,线段树,平衡树。
树状数组的常数比较小,所以优先树状数组。
code
#include<bits/stdc++.h>
using namespace std;
const int M=32010;
int tr[M]; //树状数组初始化为0,表示每个点上都没有星星
int level[M];
int lowbit(int x)
{
return x&-x;
}
//查询从[0,x]的前缀和,即[0,x]的星星的个数
int query(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))
res+=tr[i];
return res;
}
//给区间内某个点加上v值
void add(int x,int v)
{
for(int i=x;i<M;i+=lowbit(i))
tr[i]+=v;
}
int main()
{
int n;cin>>n;
for(int i=0;i<n;i++)
{
int x,y;cin>>x>>y;
x++; //树状数组的下标从1开始
int t=query(x); //求一下[0,x]的前缀和,即<=x的星星个数
level[t]++; //下一轮
add(x,1); //给点x加上1,表示该位置上有星星
}
for(int i=0;i<n;i++)cout<<level[i]<<endl;
return 0;
}