点击打开链接poj2352
思路:树状数组
分析:
1 题目是要求出每一个点的左下(正左+正下)有几个星星,那个这个点就是第几层,最后输出0~n-1层的点的个数。比如样列编号为5的星星,左下有3个星星那么5就处于第三层
2 利用树状数组,我们知道树状数组C中,C[i]表示的是原先数组A中的某一段和。题目明确指出输入的时候是按照y值增大的顺序(y相同是x增大),那么我们应该要用什么做为原先的数组A呢,很显然就是X轴,就是A[2]表示x = 2的点的个数。那么当新加入一个点的x值为2的时候,A[2]++,这个时候就是要更新C[2],C[2+lowbit(2)]...
3 那怎么求某个点的左下有几个星星呢,很显然处在左下的点的x值肯定小于等于当前点的,那么就是相当与树状数组求和,那么整道题的思路就完成
4 注意更新树状数组的时候,注意x<=MAXN,不是输入的n。因为更改了A[x],就要更新C[x] , C[x+lowbit(x)]...
5 题目输入的x的坐标可能为0,所以这边我们把所有的x+1,这就避免了TLE
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 32010; int n , ans[MAXN]; int treeNum[MAXN]; int lowbit(int x){ return x&(-x); } int getSum(int x){ int sum = 0; while(x){ sum += treeNum[x]; x -= lowbit(x); } return sum; } void add(int x , int val){ while(x < MAXN){ treeNum[x] += val; x += lowbit(x); } } int main(){ int x , y; while(scanf("%d" , &n) != EOF){ memset(treeNum , 0 , sizeof(treeNum)); memset(ans , 0 , sizeof(ans)); for(int i = 0 ; i < n ; i++){ scanf("%d%d" , &x , &y); x++; ans[getSum(x)]++; add(x , 1); } for(int i = 0 ; i < n ; i++) printf("%d\n" , ans[i]); } return 0; }
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; #define MAXN 32010 struct Node{ int left; int right; int sum; }; Node node[4*MAXN]; int vis[MAXN]; /*建立一颗线段树*/ void buildTree(int left , int right , int pos){ node[pos].left = left; node[pos].right = right; node[pos].sum = 0; if(left == right) return; int mid = (left+right)>>1; buildTree(left , mid , pos<<1); buildTree(mid+1 , right , (pos<<1)+1); } /*单点更新*/ void update(int index , int pos){ if(node[pos].left == node[pos].right){ node[pos].sum++; return; } int mid = (node[pos].left+node[pos].right)>>1; if(index <= mid) update(index , pos<<1); else update(index , (pos<<1)+1); node[pos].sum = node[pos<<1].sum + node[(pos<<1)+1].sum; } /*区间查询*/ int query(int left , int right , int pos){ if(node[pos].left == left && node[pos].right == right) return node[pos].sum; int mid = (node[pos].left+node[pos].right)>>1; if(right <= mid) return query(left , right , pos<<1); else if(left > mid) return query(left , right , (pos<<1)+1); else return query(left , mid , pos<<1)+query(mid+1 , right , (pos<<1)+1); } int main(){ int Case , n; int x , y; scanf("%d" , &Case); n = Case; buildTree(0 , MAXN , 1); memset(vis , 0 , sizeof(vis)); while(Case--){ scanf("%d%d" , &x , &y); vis[query(0 , x , 1)]++; update(x , 1); } for(int i = 0 ; i < n ; i++) printf("%d\n" , vis[i]); return 0; }