动态凸包
分别用两个std::map: 与 来维护上下凸包。需要支持:
- 单点加入
- 单点询问与凸包位置关系
其中 表示的是凸包上横坐标为 的点的纵坐标,即。
// 代码部分参考:https://www.luogu.com.cn/paste/lto905of
#include<bits/stdc++.h>
using namespace std;
const double cd = 0.0000001;
int q, opt, x, y;
struct str1 {
double a, b;
str1() {
a = b = 0;
}
str1(double A, double B) {
a = A;
b = B;
}
double d(double x) {
return a * x + b;
}
};
struct str2 {
str1 mx;
int i1, i2;
str2() {
mx = str1(-1e9, -1e9);
i1 = i2 = 0;
}
};
struct str3 {
int tot, root;
str2 num[100005];
void v(int& i7, double l, double r, str1 s, int dep) {
if (l > r || !dep) {
return;
}
if (!i7) {
i7 = ++tot;
}
if (num[i7].mx.d((l + r) / 2.0) < s.d((l + r) / 2.0)) {
swap(num[i7].mx, s);
}
if (num[i7].mx.d(l) < s.d(l)) {
v(num[i7].i1, l, (l + r) / 2.0, s, dep - 1);
}
if (num[i7].mx.d(r) < s.d(r)) {
v(num[i7].i2, (l + r) / 2.0, r, s, dep - 1);
}
}
bool query(int rt, double l, double r, str1 ss, double ll, double rr) {
double lll, rrr;
if (ll > rr) {
return 0;
}
if (!rt || (ll <= (l + r) / 2.0 && (l + r) / 2.0 <= rr && num[rt].mx.d((l + r) / 2.0) < ss.d((l + r) / 2.0))) {
return 1;
}
lll = ll;
rrr = rr;
if (num[rt].mx.d(l) < ss.d(l) || num[rt].mx.d((l + r) / 2.0) < ss.d((l + r) / 2.0)) {
rr = min(rr, (l + r) / 2.0);
if (num[rt].mx.d(ll) > ss.d(ll)) {
ll = max(ll, (num[rt].mx.b - ss.b) / (ss.a - num[rt].mx.a)) + cd;
}
if (num[rt].mx.d(rr) > ss.d(rr)) {
rr = min(rr, (num[rt].mx.b - ss.b) / (ss.a - num[rt].mx.a)) - cd;
}
if (query(num[rt].i1, l, (l + r) / 2.0, ss, ll, rr)) {
return 1;
}
}
if (num[rt].mx.d(r) < ss.d(r) || num[rt].mx.d((l + r) / 2.0) < ss.d((l + r) / 2.0)) {
ll = max(lll, (l + r) / 2.0);
rr = rrr;
if (num[rt].mx.d(ll) > ss.d(ll)) {
ll = max(ll, (num[rt].mx.b - ss.b) / (ss.a - num[rt].mx.a)) + cd;
}
if (num[rt].mx.d(rr) > ss.d(rr)) {
rr = min(rr, (num[rt].mx.b - ss.b) / (ss.a - num[rt].mx.a)) - cd;
}
if (query(num[rt].i2, (l + r) / 2.0, r, ss, ll, rr)) {
return 1;
}
}
return 0;
}
} A[4];
int main() {
cin >> q;
for (int i = 1; i <= q; i++) {
cin >> opt >> x >> y;
if (opt == 1) {
A[0].v(A[0].root, 0.0, 1.0, str1(1.0 * x + 1.0 * y, -1.0 * y), 15);
A[1].v(A[1].root, 0.0, 1.0, str1(1.0 * x - 1.0 * y, 1.0 * y), 15);
A[2].v(A[2].root, 0.0, 1.0, str1(-1.0 * x - 1.0 * y, 1.0 * y), 15);
A[3].v(A[3].root, 0.0, 1.0, str1(1.0 * y - 1.0 * x, -1.0 * y), 15);
}
else {
if (A[0].query(A[0].root, 0.0, 1.0, str1(1.0 * x + 1.0 * y, -1.0 * y), 0.0, 1.0)) {
cout << "NO\n";
continue;
}
if (A[1].query(A[1].root, 0.0, 1.0, str1(1.0 * x - 1.0 * y, 1.0 * y), 0.0, 1.0)) {
cout << "NO\n";
continue;
}
if (A[2].query(A[2].root, 0.0, 1.0, str1(-1.0 * x - 1.0 * y, 1.0 * y), 0.0, 1.0)) {
cout << "NO\n";
continue;
}
if (A[3].query(A[3].root, 0.0, 1.0, str1(1.0 * y - 1.0 * x, -1.0 * y), 0.0, 1.0)) {
cout << "NO\n";
continue;
}
cout << "YES\n";
}
}
return 0;
}
代码短,跑得还快,真香~
自此,我们已经写学习了动态凸包所需的所有操作!
模板:CF70D. Professor's task
题解仅供学习参考使用
抄袭、复制题解,以达到刷 AC 率/AC 数量或其他目的的行为,在洛谷是严格禁止的。
洛谷非常重视学术诚信。此类行为将会导致您成为作弊者。 具体细则请查看