UVA11020 Efficient Solutions——multiset+思维

题目传送门

文章目录

题意

  • 对于集合 S S S中的点 A ( x a , y a ) A(x_a,y_a) A(xa,ya), 不存在另一个点 B ( x b , y b ) B(x_b,y_b) B(xb,yb), 使得 x b ≤ x a 且 y b < y a x_b\leq x_a 且 y_b < y_a xbxayb<ya 或者 x b < x a 且 y b ≤ y a x_b < x_a 且 y_b \leq y_a xb<xaybya,那么我们称A为优势点
  • 现在有n个点,每个点动态的插入集合S中,求集合S中当前优势点的个数

思路

  • 我们维护一个集合 s s s s s s中只含有优势点。对于每次插入修改 s s s中的值,再输出 s . s i z e ( ) s.size() s.size()即可
  • 那么如何维护? 我们利用stl中的multiset自动排序的性质,自定义排序规则:按照x从小到大排序,x相同就按照y从小到大排序。
  • 对于集合中的点p, p左边的点会决定P是否为优势点,而p会决定它右边的点是否为优势点
  • 当新插入一个点 p ( x p , y p ) p(x_p,y_p) p(xp,yp)时找到第一个大于等于点 p p p的点 q q q, 如果找不到或者找到的点 q q q的前一个点 o o o, o . y > p . y o.y>p.y o.y>p.y,那么则插入点 p p p
  • 插入后要删除集合当中失去优势的点,upper_bound找到第一个大于点 p p p的点 r r r, 从 r r r往后看,如果当前的点的y>=p.y,那么则删除当前点
    -集合s中原本不是优势点的,插入p后依然不是优势点, 所以删除后对后续操作没影响

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+9; 
struct Point
{
	int x,y;
	//定义排序规则 
	bool operator<(const Point &t) const
	{
		if(x!=t.x) return x<t.x;
		else return y<t.y;
	}
};
//维护一个集合,这个集合里面的所有的点都是优势点 
multiset<struct Point> s;
int main()
{
	
	int t;
	cin>>t;
	int cnt=0;
	while(t--)
	{
		//注意输出这个
		printf("Case #%d:\n",++cnt);
		int n;
		struct Point p;
		//每次记得清除集合S里面的值 
		s.clear(); 
		scanf("%d",&n);
		multiset<struct Point>:: iterator it;
		for(int i=0; i<n; i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			p={x,y};
			//set或者multiset lower_bound()返回的是第一个大于等于x的迭代器; 
			//nlogn ,找到第一个元素e,e.x>=p.x ,只有当集合为空
			//或者e的前一个元素的的y值大于p.y 
			//这里如果s为空,返回s.end(),此时s.end()==s.begin(),
			it=s.lower_bound(p); 
			if(it==s.begin()||(--it)->y>y) 
			{
				s.insert(p);
				//找到第一个元素e,e.x>p.x 
				it=s.upper_bound(p);
				while(it!=s.end()&&it->y>=y) s.erase(it++);
			}
			printf("%d\n",(int)s.size());
		}
		//注意格式
		if(t) puts("");
	} 
	return 0;
 } 
posted @ 2022-08-28 08:43  翔村亲亲鸟  阅读(8)  评论(0编辑  收藏  举报