UVA11020 Efficient Solutions

题目链接

题目

见链接。

题解

知识点:STL,二分。

首先不考虑新加入的操作,先考虑一个固定的局面,给定了所有人的两个属性值 LC,找出有竞争力的人。

这类双变量的条件一般可以画在坐标系 LC 查看,发现如果一个点坐标到原点构成的矩形内部(包括边,但不包括这个点本身)有其他点,则这个点就没有竞争力。

于是发现竞争力人群规律, L 小的人相对于其他人 C 会较大,而 L 大的人相对于其他人 C 会较小。因为对于一个 L 小的人,那么后面 L 大的人 C 要比 L 小的人的 C 小,不然就没竞争力,所以整体会呈现一个反比例函数的形式。

接下来,容器要满足排序,插入,删除,查找,且元素可能重复,因此用 multiset 。为了方便查找,我们对列表按 L 为第一关键字从小到大排, C 为第二关键字从小到大排。

现在考虑插入一个人,我们先在坐标系中往他左边看,判断他能不能插入。具体的说,我们要找到 L 小于他的人中 C 最小的人,这个人是最有可能使他失去优势的人。根据我们之前分析的特性, L 越大 C 越小,因此需要找到最后一个 L 小于他或者 L 等于他但 C 小于等于他的人。为此,我们需要使用 lower_bound 找到第一个 L 大于他或者 L 等于他但 C 大于等于他的人,这个人的前一个人就是我们要找的人。如果没有找到,或者找到的人 C 大于他,那么他就能插入,否则不能。

如果能插入,我们在坐标系中往他右边看,开始排除后面需要踢掉的人。具体的说,我们要踢掉所有 L 大于他且 C 大于等于他或者 L 等于他且 C 大于他的人。根据我们之前分析的特性, L 越大 C 越小,因此从第一个 L 大于他或者 L 等于他但 C 大于他的人开始踢,我们可以用 upper_bound 实现。随后开始向后遍历,我们只要踢到第一个 C 小于他的人之前即可,后面的 C 更小不需要考虑。

最后容器大小就是有竞争力的人的人数。

时间复杂度 O(nlogn)

空间复杂度 O(n)

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
struct node {
int x, y;
friend bool operator<(node a, node b) {
return a.x == b.x ? a.y < b.y : a.x < b.x;
}
};
bool solve() {
int n;
cin >> n;
multiset<node> ms;
for (int i = 0, x, y;i < n;i++) {
cin >> x >> y;
node a = { x,y };
auto it = ms.lower_bound(a);//找到最有可能使a失去优势的人
if (it == ms.begin() || (--it)->y > y) {//a有优势
it = ms.insert(a);
it = ms.upper_bound(a);//第一个没有优势的人
while (it != ms.end() && it->y >= y) it = ms.erase(it);
}
cout << ms.size() << '\n';
}
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
int cnt = 1;
while (t--) {
cout << "Case #" << cnt++ << ":" << '\n';
if (!solve()) cout << -1 << '\n';
cout << (t ? "\n" : "");
}
return 0;
}
posted @   空白菌  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示