B - Efficient Solutions UVA - 11020
题意:
给你n个人,每个人有两个属性x,y。如果对于一个人p(x,y),不存在另一个人(a,b),使得a<x,b<=y或者a<=x,b<y,则认为这个人是有优势的。
思路(雨神)
动态插入每个人,统计已插入的人中,有优势的人的个数。
插入时,维护的集合,应该是上面的形状。假如插入p时,有(a,b)是在(x,y)这个矩形的外面时,就出去了。
反思
- 第一次做时,没有把题意转换成上面那张图,想了挺久的qwq。
- 输出格式也要注意一下,之前碰到过一次。
- 由于要用multiset和lower_bound时要自定义(重载)
struct point
{
int x,y;
bool operator <(const point &b)const
{
if(x==b.x)return y<b.y;
return x<b.x;
}
};
multiset<point>p;
- 之后每插入集合中的元素都满足上面的图。
- 维护时,把不满足的点去掉即可。(用二分加快搜索速度)
multiset <point>::iterator it=p.lower_bound(temp);
//二分找到>=TEMP的点。
if(it==p.begin()||(--it)->y>temp.y)
{
//如果是第一个比temp大要进去,即比第一个还小。
//或者要满足上图的条件,前一个点要y>temp的y
p.insert(temp);
it=p.upper_bound(temp);
//找到第一个严格大于temp的值,把它出集合
while(it!=p.end()&&it->y>=temp.y)p.erase(it++);
//找不到就会it==p.end,或者剩下的点是满足条件的。
}
AC
#include <iostream>
#include <set>
#include <cstdio>
#include <vector>
#include <algorithm>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
struct point
{
int x,y;
bool operator <(const point &b)const
{
if(x==b.x)return y<b.y;
return x<b.x;
}
};
multiset<point>p;
int main()
{
int t,kase=0;
scanf("%d", &t);
while(t--)
{
p.clear();
vector<int>ans;
int n;
scanf("%d", &n);
For(i,1,n)
{
point temp;
scanf("%d%d", &temp.x,&temp.y);
multiset <point>::iterator it=p.lower_bound(temp);
if(it==p.begin()||(--it)->y>temp.y)
{
p.insert(temp);
it=p.upper_bound(temp);
while(it!=p.end()&&it->y>=temp.y)p.erase(it++);
}
// printf("%d\n", p.size());
int len=p.size();
ans.push_back(len);
}
if(kase!=0)printf("\n");
printf("Case #%d:\n", ++kase);
For(i,0,n-1)printf("%d\n",ans[i]);
//printf("\n");
}
return 0;
}