tkj
文章143
标签102
分类0
bzoj 2961: 共点圆 & bzoj 4140: 共点圆加强版

bzoj 2961: 共点圆 & bzoj 4140: 共点圆加强版

题意:

动态加入过原点的圆,询问一个点是否在所有圆内或圆上。加强版要强制在线。

题解:

设第$i$个圆$C_i$的方程为$(x - x_i) ^ 2 + (y - y_i) ^ 2 = x_i ^ 2 + y_i ^ 2$,则点$P(x_0, y_0)$要在$\odot C_i$中,就要满足$$
(x_0 - x_i) ^ 2 + (y_0 - y_i) ^ 2 \le x_i ^ 2 + y_i ^ 2 \\\
x_0 ^ 2 + y_0 ^ 2 \le 2 (x_0 x_i + y_0 y_i)

x_0 ^ 2 + y_0 ^ 2 \le 2 \min \lbrace x_0 x_i + y_0 y_i \rbrace

$$
设$z = x_0 x_i + y_0 y_i$,则$y_i = -\frac{x_0}{y_0} + \frac z {y_0}$。$z$取最小值时,$(x_i, y_i)$一定在下凸包上,用splay维护一下就好了。

代码:

强制在线版

#include <bits/stdc++.h>
using namespace std;

int n, cnt = 0;
const double eps = 1e-12, inf = 1e40;
struct pnt
{
    double x, y;
    pnt() {}
    pnt(double x, double y) : x(x), y(y) {}
};
pnt operator+(pnt x, pnt y) { return pnt(x.x + y.x, x.y + y.y); }
pnt operator-(pnt x, pnt y) { return pnt(x.x - y.x, x.y - y.y); }
double operator*(pnt x, pnt y) { return x.x * y.y - x.y * y.x; }

struct tree
{
    pnt x;
    double k;
    tree *f, *s[2];
    tree(pnt x) : x(x), f(NULL), s() {}
} *root;

double get_k(pnt x, pnt y) { return (y.y - x.y) / (y.x - x.x); }
void rot(tree *x)
{
    tree *f = x->f, *ff = f->f;
    int w = x == f->s[0];
    f->s[w ^ 1] = x->s[w];
    if (x->s[w]) x->s[w]->f = f;
    if (ff) ff->s[f == ff->s[1]] = x;
    x->f = ff;
    x->s[w] = f;
    f->f = x;
}
void splay(tree *x, tree *rt)
{
    while (x->f != rt)
    {
        tree *f = x->f, *ff = f->f;
        if (ff == rt) rot(x);
        else if ((x == f->s[0]) == (f == ff->s[0])) rot(f), rot(x);
        else rot(x), rot(x);
    }
    if (!rt) root = x;
}
tree *fd(pnt x)
{
    tree *p = root, *f;
    while (p)
    {
        f = p;
        if (x.x + eps < p->x.x) p = p->s[0];
        else if (x.x - eps > p->x.x) p = p->s[1];
        else return p;
    }
    return f;
}
tree *pre(tree *x)
{
    if (!x) return x;
    splay(x, 0);
    x = x->s[0];
    if (!x) return x;
    while (x->s[1]) x = x->s[1];
    return x;
}
tree *nxt(tree *x)
{
    if (!x) return x;
    splay(x, 0);
    x = x->s[1];
    if (!x) return x;
    while (x->s[0]) x = x->s[0];
    return x;
}
void erase(tree *x)
{
    splay(x, 0);
    if (!x->s[0] && !x->s[1]) root = NULL;
    else if (!x->s[0] && x->s[1]) root = x->s[1], x->s[1]->f = NULL, x->s[1]->k = -inf;
    else if (x->s[0] && !x->s[1]) root = x->s[0], x->s[0]->f = NULL;
    else
    {
        tree *hh = x->s[0];
        while (hh->s[1]) hh = hh->s[1];
        splay(hh, x);
        hh->s[1] = x->s[1];
        x->s[1]->f = hh;
        hh->f = NULL;
        root = hh;
        tree *oo = nxt(root);
        splay(oo, root);
        oo->k = get_k(root->x, oo->x);
    }
    delete x;
}
void insert(pnt x)
{
    if (!root)
    {
        root = new tree(x);
        root->k = -inf;
    }
    else
    {
        tree *p = fd(x);
        if (abs(p->x.x - x.x) < eps)
        {
            if (x.y > p->x.y + eps) return;
            p->x = x;
        }
        else if (x.x > p->x.x)
        {
            p->s[1] = new tree(x);
            p->s[1]->f = p;
            p = p->s[1];
        }
        else
        {
            p->s[0] = new tree(x);
            p->s[0]->f = p;
            p = p->s[0];
        }
        splay(p, 0);
        tree *l = pre(p), *r = nxt(p);
        // if (l) printf("l: (%lf, %lf) %lf\n", l->x.x, l->x.y, l->k);
        // if (r) printf("r: (%lf, %lf) %lf\n", r->x.x, r->x.y, r->k);
        if (l && r && (r->x - l->x) * (p->x - l->x) > eps)
        {
            // puts("a");
            erase(p);
            return;
        }
        tree *l1 = pre(p), *l2 = pre(l1);
        while (l2)
        {
            if ((x - l2->x) * (l1->x - l2->x) > eps) erase(l1);
            l1 = l2;
            l2 = pre(l2);
        }
        tree *r1 = nxt(p), *r2 = nxt(r1);
        while (r2)
        {
            if ((r2->x - x) * (r1->x - x) > eps) erase(r1);
            r1 = r2;
            r2 = nxt(r2);
        }
        l = pre(p), r = nxt(p);
        if (l) p->k = get_k(p->x, l->x); else p->k = -inf;
        if (r) r->k = get_k(r->x, p->x);
    }
}
tree *fd(double x)
{
    tree *p = root, *f = NULL;
    while (p)
    {
        f = p;
        if (x + eps < p->k) p = p->s[0];
        else if (x - eps > p->k) p = p->s[1];
        else return p;
    }
    p = f;
    if (p && p->k > x) p = pre(p);
    return p;
}
void print(tree *x)
{
    if (!x) return;
    print(x->s[0]);
    printf("(%lf, %lf) %lf\n", x->x.x, x->x.y, x->k);
    print(x->s[1]);
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        int op;
        double x, y;
        scanf("%d%lf%lf", &op, &x, &y);
        x += cnt;
        y += cnt;
        if (op == 0) insert(pnt(x, y));
        else
        {
            tree *p = fd(-x / y);
            // printf("(%lf, %lf)\n", p->x.x, p->x.y);
            puts(p && x * x + y * y <= 2 * (x * p->x.x + y * p->x.y) ? (cnt++, "Yes") : "No");
        }
        // print(root);
    }
}
本文作者:tkj
本文链接:https://tkj666.github.io/112/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可