POJ - 2352 树状数组 + 思维

题目大意:给定n对x与y坐标 ,求[0,n-1]不同等级下的点的个数。每个点的等级取决于:位于该点下方以及左方的点的个数。

思路:利用一个树状数组维护不同区间下星星的个数;对输入的坐标对按照y排序,y相同的按照x排序(升序)。这样一来,直接使用树状数组维护[1,x]的星星的个数即可,因为每次新加入树状数组的点的等级必将大于等于上一个点的等级。题目给出的坐标可能是0,所以对x坐标进行+1处理

使用ANS数组的思维:使用ANS数组去保存各个等级的点的个数。先获得加入树状数组的点 i 的等级,然后以等级为下标对ANS数组的元素递增;之后将树状数组的区间[1,x]的星星个数加1更新。

一定要注意求等级和区间更新的先后顺序,因为本题中,点的等级不包括自身,所以需要先求等级再递增。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 15005;
int n, msum[maxn << 2], x, y, ANS[maxn];
struct Node{
	int x, y;
}node[maxn];

bool cmp(Node a, Node b){
	if(a.y == b.y) return a.x < b.x;
	return a.y < b.y;
}

void update(int x, int v){
	//要更新维护区间内的所有地方 ,因为,题目中给的x坐标并不知规定小于n。所以加lowbit 一直到maxn << 2. 
	for(int i = x; i <= maxn << 2;i += i & (-i)){	 
		msum[i] += v;
	}
}

int getNum(int x){
	int ans = 0;
	for(int i = x;i > 0; i -= i & (-i)){
		ans += msum[i];
	}
	return ans;
}

int main(){
	while(scanf("%d", &n) != EOF){
		memset(ANS, 0, sizeof ANS);
		memset(node, 0, sizeof node);
		for(int i = 1;i <= n;i++){
			scanf("%d%d", &node[i].x, &node[i].y);
			node[i].x++;//该题需要防止下标为0; 
		}
		sort(node + 1, node + n + 1, cmp);
		//依次加入树状数组进行维护
		for(int i = 1; i <= n;i++) {
			ANS[getNum(node[i].x)]++;//等级为getNum(node[i].x)的星星数+1 
			update(node[i].x, 1);//更新维护区间,星星数加1 
		}
		for(int i = 0;i < n;i++){
			printf("%d\n",ANS[i]);
		}
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40596572/article/details/103997044