Brownie Points II 题解
教练布置的扫描线题,但是感觉算不上那种经典的扫描线。
先手选择的是一条垂直于横坐标轴的直线,并且因为这条线必须穿过某个点,所以可以直接枚举这一条直线。
可以先将所有点以横坐标为优先级升序排序,这样我们枚举这条直线的时候就是在做扫描线,可以更方便地统计答案。
我们其实要做的事情是:维护直线两边的点的纵坐标,并且能够查询纵坐标大于(或小于)某个值的点的个数,支持插入和删除点。
你会发现在统计过程中我们是不用考虑直线两边的点的横坐标的,因为这条直线本身就起到了分类的作用,而对于纵坐标的维护本质上就是单点加,区间求和,很多数据结构都能做到,代码实现中是将纵坐标离散化后用树状数组维护的。
具体地,我们分以下步骤来统计:
- 使用两个树状数组,一个维护直线左边的点,一个维护直线右边的点,初始时要将所有的点加入到右边的树状数组。
- 从左至右地枚举直线,将直线上经过的点都从右边的树状数组中删除。
- 枚举后手会选择这个直线上的哪个点并更新答案。
- 将直线上经过的点加入左边的树状数组。
- 回到步骤二,直到所有的点都被扫描线扫过了。
关于更新答案这一部分,需要注意的是:本题不是博弈论,不存在“后手会为了让自己的分数超过先手,而选择某一个点使得自己的分数超过先手,但是会比自己能拿到的最大分数更劣”这种情况。只需要按照题意简单模拟即可。
应该讲得很详细了,给一份代码:
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
typedef long long ll;
int n, ans, sz, rg, Stan, Ollie, resS, resO;
set<int> s;
pair<int, int> p[200005];
vector<int> lsh;
struct BIT {
int c[200005];
void clear() {fill(c, c + sz + 1, 0);}
int lowbit(int x) {return x & (-x);}
void add(int x, int v) {
while(x <= sz) c[x] += v, x += lowbit(x);
}
int ask(int x) {
int ret = 0;
while(x) ret += c[x], x -= lowbit(x);
return ret;
}
} pre, suf;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
while(cin >> n) {
if(!n) break;
lsh.clear();
for(int i = 1; i <= n; ++i) {
cin >> p[i].first >> p[i].second;
lsh.push_back(p[i].second);
}
stable_sort(p + 1, p + 1 + n);
stable_sort(lsh.begin(), lsh.end());
lsh.erase(unique(lsh.begin(), lsh.end()), lsh.end());
sz = lsh.size();
pre.clear(), suf.clear();
for(int i = 1; i <= n; ++i) {
p[i].second = lower_bound(lsh.begin(), lsh.end(), p[i].second) - lsh.begin() + 1;
suf.add(p[i].second, 1);
}
ans = -2147483647;
for(int i = 1; i <= n; ++i) {
rg = i;
while(rg < n && p[rg + 1].first == p[i].first) ++rg;
for(int j = i; j <= rg; ++j) {
suf.add(p[j].second, -1);
}
Stan = 2147483647, Ollie = -2147483647;
for(int j = i; j <= rg; ++j) {
resS = pre.ask(p[j].second - 1) + suf.ask(sz) - suf.ask(p[j].second);
resO = pre.ask(sz) - pre.ask(p[j].second) + suf.ask(p[j].second - 1);
if(resO > Ollie) Ollie = resO;
if(resO == Ollie) Stan = min(Stan, resS);
}
if(Stan > ans) {
ans = Stan;
s.clear();
}
if(Stan == ans) s.insert(Ollie);
for(int j = i; j <= rg; ++j) {
pre.add(p[j].second, 1);
}
i = rg;
}
cout << "Stan: " << ans << "; Ollie:";
for(set<int>::iterator it = s.begin(); it != s.end(); ++it) cout << " " << *it;
cout << ";\n";
}
return 0;
}
本文来自博客园,作者:A_box_of_yogurt,转载请注明原文链接:https://www.cnblogs.com/A-box-of-yogurt/p/18016407