POJ2352题解(树状数组)
2019-12-29
Powered by Gauss
1.题目传送门:POJ2352
2.题目大意:
这是一道非常经典的树状数组的模板题。
题目大意是说,给出N颗星星,每个星星都有一个二维坐标,要求出位于每颗星星左下方的星星的数量。
3.算法思路:
这道题被给出之后立刻想到暴力法,让我们来计算一下:
根据题目,N<=15000,暴力法需要双层循环,也就是150002=225,000,000,超出了一秒,所以不得不寻求更快更好的算法思想。
当我们需要求查询,求和的时候,应该想到使用树状数组。
同时,这道题的题目条件让我们具备了使用树状数组的条件:星按Y坐标的升序列出,Y坐标相等的星按X坐标的升序排列。
这样的话我们就可以免排序在输入的循环中直接计算:
for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); level[sum(++x)]++; add(x,1); }
其中level数组用来统计等级为0-N的每一级的星星的个数。
然后让我们来看一下树状数组的标配lowbit函数和sum函数:
int sum(int x) { int ans=0; while(x>0) { ans+=a[x]; x-=lowbit(x); } return ans; }
int lowbit(int x) { return x&-x; }
这样我们就方便了滞后的统计计算,下面给出完整AC代码:
#includeusing namespace std; const int maxn=32005; int a[maxn],level[maxn],n,x,y; int lowbit(int x) { return x&-x; } void add(int x,int v) { while(x<=maxn) { a[x]+=v; x+=lowbit(x); } } int sum(int x) { int ans=0; while(x>0) { ans+=a[x]; x-=lowbit(x); } return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); level[sum(++x)]++; add(x,1); } for(int i=0;i<=n-1;i++) printf("%d\n",level[i]); return 0; }