http://acm.hdu.edu.cn/showproblem.php?pid=1156
在一张二位坐标系中,给定n个点的坐标,玩一个划线游戏(线必须穿过点),Stan先手画一条垂直的线,然后Ollie画一条水平的线(要求要穿过Stan那条线所穿过的某个点)。划分后,左上和右下点数是Ollie 的得分,左下和右上是Stan的得分。求Stan在保证最低得分(即不论Ollie后手怎么划,Stan最少能的的分数)最高,并给出基于符合的先手划法,Ollie后手的各种划线的得分(需要去重),升序输出。
这里可以发现,每次划分等同于枚举以某个点为原点,求一次局面,不同的局面分类到x轴坐标中,每个坐标中的局面集合求最小值,所有x轴坐标分类求最大值即求出了最低最大划法。
#include <iostream> #include <cstring> #include <string> #include <queue> #include <vector> #include <set> #include <stack> #include <cmath> #include <cstdio> #include <map> #include <algorithm> using namespace std; struct node { int x, y; }p[200005]; bool cmpx(node a, node b) { if (a.x == b.x) return a.y < b.y; return a.x < b.x; } const int N = 200005; map<int, int> mpx, mpy; int st[N]; int tre[N]; int ans[N]; int lowbit(int k) { return k&-k; } int query(int k) { int rec = 0; while (k) { rec += tre[k]; k -= lowbit(k); } return rec; } void add(int k) { while (k <= N) { tre[k]++; k += lowbit(k); } } bool cmp(node a, int b) { return a.x < b; } int main() { cin.sync_with_stdio(false); int n; while (cin>>n) { if (n == 0) break; mpx.clear(), mpy.clear(); queue<node> wq; fill(tre, tre + N, 0); fill(ans, ans + N, 0); for (int i = 0; i < n; i++) cin >> p[i].x>>p[i].y,mpx[p[i].x]++,mpy[p[i].y]++,st[i]=p[i].y; sort(st, st + n); int len = unique(st, st + n) - st; sort(p, p + n, cmpx); for (int i = 0; i < n; i++) { while (!wq.empty()) { node ad = wq.front(); if (ad.x < p[i].x) add(upper_bound(st, st + len, ad.y) - st + 1),wq.pop(); else break; } int py = upper_bound(st, st + len, p[i].y)-st+1; ans[i] += query(py-1); wq.push(p[i]); } while (!wq.empty()) wq.pop(); fill(tre, tre + 200005, 0); for (int i = n-1; i >= 0; i--) { while (!wq.empty()) { node ad = wq.front(); if (ad.x > p[i].x) add(len+st-upper_bound(st, st + len, ad.y) + 1),wq.pop(); else break; } int py = len + st - upper_bound(st, st + len, p[i].y) + 1; ans[i] += query(py-1); wq.push(p[i]); } map<int, int> getMi; for (int i = 0; i < n; i++) { if (getMi.find(p[i].x) == getMi.end()) getMi[p[i].x] = ans[i]; else getMi[p[i].x] = min(getMi[p[i].x], ans[i]); } map<int, int>::iterator mxit = getMi.end(); for (map<int, int>::iterator it = getMi.begin(); it != getMi.end(); it++) { if (mxit == getMi.end()) mxit = it; else if (mxit->second < it->second) mxit = it; } cout << "Stan: " << mxit->second << "; Ollie:"; set<int> rpy; for (int i = 0; i < n; i++) if (getMi[p[i].x]==ans[i]&&ans[i] == mxit->second) rpy.insert(n - ans[i] - mpx[p[i].x] - mpy[p[i].y] + 1); for (set<int>::iterator it = rpy.begin(); it != rpy.end(); it++) { cout << ' ' << *it; } cout << ";" << endl; } return 0; }