[并查集]Baltic OI 2016 Park

来源:互联网 发布:淘宝达人什么意思 编辑:程序博客网 时间:2024/05/17 07:57

Description

给定W×H的平面。四个角落分别是四个出入口。
n个圆,用三元组(x,y,r)表示。
m个人,用二元组(r,e)表示。
求每个人不与任何圆相交可以到达哪些出入口。

Solution

考虑离线。
O(n2)个每两个圆之间的最短距离排序。
m个人的直径排序。
n个圆和上下左右四个边界看成节点。
考虑把圆按顺序加入图内,用并查集维护连通性。
分类讨论每两个边界联通后会导致四个角落连通性的变化。
根本看不懂标程疯狂使用c++11的特性,反正跑得比我慢得多。。

using namespace std;const double eps = 1e-4;const int N = 2020;const int M = 101010;typedef long long ll;inline char get(void) {    static char buf[100000], *S = buf, *T = buf;    if (S == T) {        T = (S = buf) + fread(buf, 1, 100000, stdin);        if (S == T) return EOF;    }    return *S++;}template<typename T>inline void read(T &x) {    static char c; x = 0;    for (c = get(); c < '0' || c > '9'; c = get());    for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';}struct Point {    ll x, y, r;    inline double operator -(const Point &a) {        return (sqrt((x - a.x) * (x - a.x) + (y - a.y) * (y - a.y))) - r - a.r;    }};struct cpp {    ll x, id, r;    inline bool operator <(const cpp &a) const{        return r < a.r;    }};struct PPairs {    ll x, y;    double d;    inline bool operator <(const PPairs &a) const {        return d < a.d;    }    PPairs(double _d = 0, ll _x = 0, ll _y = 0):x(_x), y(_y), d(_d) {}};Point p[N];cpp a[M];PPairs d[N * N];int n, m, w, h, p1, dnt;int fa[N], rk[N];int ans[M][5];int mp[5][5];inline int Fa(int x) {    return x == fa[x] ? x : fa[x] = Fa(fa[x]);}inline int Merge(int x, int y) {    static int f1, f2;    f1 = Fa(x); f2 = Fa(y);    if (f1 == f2) return false;    if (rk[f1] > rk[f2]) swap(f1, f2);    if (rk[f1] == rk[f2]) ++rk[f2];    fa[f1] = f2; return true;}inline void Link(int x, int y) {    mp[x][y] = mp[y][x] = 0;}// n + 1 up, n + 2 down, n + 3 left and n + 4 right// 1 = bottom-left, 2 = bottom-right, 3 = top-right, 4 = top-leftint main(void) {    freopen("park.in", "r", stdin);    freopen("park.out", "w", stdout);    read(n); read(m);    read(w); read(h);    for (int i = 1; i <= n; i++) {        read(p[i].x); read(p[i].y); read(p[i].r);    }    for (int i = 1; i <= m; i++) {        read(a[i].r); read(a[i].x);        a[i].r *= 2; a[i].id = i;    }    for (int i = 1; i <= n; i++) {        d[++dnt] = PPairs(h - p[i].y - p[i].r, i, n + 1);        d[++dnt] = PPairs(p[i].y - p[i].r, i, n + 2);        d[++dnt] = PPairs(p[i].x - p[i].r, i, n + 3);        d[++dnt] = PPairs(w - p[i].x - p[i].r, i, n + 4);        for (int j = i + 1; j <= n; j++)            d[++dnt] = PPairs(fabs(p[j] - p[i]), i, j);    }    sort(d + 1, d + dnt + 1);    sort(a + 1, a + m + 1);    for (int i = 1; i <= n + 4; i++) fa[i] = i;    p1 = 1;    for (int i = 1; i <= 4; i++)        for (int j = 1; j <= 4; j++)            mp[i][j] = 1;    for (int i = 1; i <= m; i++) {        while (d[p1].d + eps < a[i].r && p1 <= dnt) {            Merge(d[p1].x, d[p1].y); ++p1;        }        if (Fa(n + 1) == Fa(n + 2)) {            Link(1, 2); Link(1, 3);            Link(4, 2); Link(4, 3);        }        if (Fa(n + 1) == Fa(n + 3)) {            Link(4, 1); Link(4, 2);            Link(4, 3);        }        if (Fa(n + 1) == Fa(n + 4)) {            Link(3, 1); Link(3, 2);            Link(3, 4);        }        if (Fa(n + 2) == Fa(n + 3)) {            Link(1, 2); Link(1, 3);            Link(1, 4);        }        if (Fa(n + 2) == Fa(n + 4)) {            Link(2, 1); Link(2, 3);            Link(2, 4);        }        if (Fa(n + 3) == Fa(n + 4)) {            Link(1, 3); Link(1, 4);            Link(2, 3); Link(2, 4);        }        for (int j = 1; j <= 4; j++)            ans[a[i].id][j] = mp[a[i].x][j];    }    for (int i = 1; i <= m; i++) {        for (int j = 1; j <= 4; j++)            if (ans[i][j]) putchar('0' + j);        putchar('\n');    }    return 0;}
原创粉丝点击