UVa 11020 排序二叉树

题目链接

题目大意:有n个人,每个人有两个属性x,y,如果对于一个人P(x,y),不存在另外一个人(a,b),使得a<x, b <= y 或者 a < = x, b < y, 则这个人是有优势的。

动态插入每个人,要求统计当前已经插入的人中, 有优势的人的个数。

注意可能出现2个人的x,y都相等的情况,即重复。


思路:用二叉树保存已插入而且有优势的人的信息。先按x小的排,再按y小的排, 把每个人看成一个点操作。

插入操作:当我们要插入一个点p时, 先判断其是否有优势, 若有则插入,没有则跳过。 判断其是否有优势: 找到与其最接近的2个点(lower_bound找出其中一个点),比较点p左边的点和点p的y值的大小即可。

删除操作:对于一个点的插入可能引起其它点的优势失去,所以要删除这些点, 我们可以从第一个比它大的点开始找(之前的点一定是有优势的,用upper_bound找出这个点),往后删除失去优势的点。


插入总体复杂度 O(n * log (n) ), 由于失去优势的点在以后的操作中不可能再有优势,所以删除总体复杂度 O(n * log(n))。

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

struct point{
	int x, y;
	bool operator < (const point &t) const{
		return x < t.x || (x == t.x && y <t.y);
	}
};
multiset <point> s;
multiset <point>::iterator it;

int main(){
	int i, j, cas, n;
	scanf("%d", &cas);
	for(int ca = 1; ca <= cas; ca++){
		scanf("%d", &n);
		int x, y;
		s.clear();
		printf("Case #%d:\n", ca);
		while(n--){
			scanf("%d%d", &x, &y);
			point p = (point) {x, y};
			it = s.lower_bound(p);
			if(it == s.begin() || (--it)->y > y){
				s.insert(p);
				it = s.upper_bound(p);
				while(it != s.end() && it->y >= y)
					s.erase(it++);
			}
			printf("%d\n", s.size());
		}
		if(ca != cas) puts("");
	}
	return 0;
}


你可能感兴趣的:(UVa 11020 排序二叉树)