题解 P4073 【[WC2013]平面图】

· · 题解

其实如果你对平面图相关的东西非常熟悉的话这题就是个板子题,只要跑个平面图转对偶图,然后对询问的点在平面图上点定位找到所在区域,然后就是Noip货车运输那个题了……在最小生成树上查询最大边权即可。

如果你不会平面图转对偶图的话可以去这题的题解里学习一下,这里简单说一下平面图点定位,就是我们希望找到给定点在平面图上所在的区域,这个我们扫描线+平衡树解决。我们知道计算几何里很多东西都是那种相对顺序不改变的,就可以扫描线,这个平面图也是如此。我们把关键点与询问点从左到右排序,然后开一个平衡树维护当前加入的边,这个边我们应该从左指向右,在这条边上存边下面的这个区域编号,就像这样:

然后对于这个询问点我们去平衡树上二分它上面的第一条边(如果没有那他在外部区域里),这样就能找了。注意为了避免特殊情况我们需要在平衡树上操作的时候对x加或减一个eps。

另外由于是“插入时的相对顺序不变”,所以在这里不能用懒惰删除的替罪羊树(因为删完了点还留在树上就乱套了……我开始写了个替罪羊树怎么也过不去……)。

上代码~

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
#define opp(_o) (_o == ch[fa[_o]][1])
using namespace std;
namespace ywy {
    inline int get() {
        int n = 0;
        char c;
        while ((c = getchar()) || 23333) {
            if (c >= '0' && c <= '9')
                break;
            if (c == '-')
                goto s;
        }
        n = c - '0';
        while ((c = getchar()) || 23333) {
            if (c >= '0' && c <= '9')
                n = n * 10 + c - '0';
            else
                return (n);
        }
    s:
        while ((c = getchar()) || 23333) {
            if (c >= '0' && c <= '9')
                n = n * 10 - c + '0';
            else
                return (n);
        }
    }
    namespace tree {
    typedef struct _b {
        int dest;
        int nxt;
        int len;
    } bian;
    bian memchi[1000001];
    int gn = 1, heads[100001];
    inline void add(int s, int t, int l) {
        memchi[gn].dest = t;
        memchi[gn].len = l;
        memchi[gn].nxt = heads[s];
        heads[s] = gn;
        gn++;
    }
    int ance[100001][17], mx[100001][17], deep[100001];
    void dfs(int pt, int baba) {
        for (register int i = heads[pt]; i; i = memchi[i].nxt) {
            if (memchi[i].dest == baba)
                continue;
            deep[memchi[i].dest] = deep[pt] + 1;
            ance[memchi[i].dest][0] = pt;
            mx[memchi[i].dest][0] = memchi[i].len;
            dfs(memchi[i].dest, pt);
        }
    }
    inline int lca(int a, int b) {
        if (deep[a] > deep[b])
            swap(a, b);
        int maxn = 0;
        for (register int i = 16; i >= 0; i--) {
            if (deep[ance[b][i]] >= deep[a])
                maxn = max(maxn, mx[b][i]), b = ance[b][i];
        }
        if (a == b)
            return (maxn);
        for (register int i = 16; i >= 0; i--) {
            if (ance[a][i] != ance[b][i]) {
                maxn = max(maxn, max(mx[a][i], mx[b][i]));
                a = ance[a][i];
                b = ance[b][i];
            }
        }
        return (max(maxn, max(mx[a][0], mx[b][0])));
    }
    }  // namespace tree
    int ints[100001];
    int find(int n) {
        if (ints[n] == n)
            return (n);
        return (ints[n] = find(ints[n]));
    }
    unsigned char gg[1000001];
    typedef struct _b {
        int s;
        int t;
        int l;
        friend bool operator<(const _b &a, const _b &b) { return (a.l < b.l); }
    } xiabb;
    xiabb bians[200001];
    double dx;
    typedef struct _n {
        double k, b;
        int id;
        friend bool operator<(const _n &a, const _n &b) { return (a.k * dx + a.b < b.k * dx + b.b); }
    } node;
    int root = 0;
    int ch[1000001][2], fa[1000001];
    node data[1000001];
    int gn = 1;
    inline void xuan(int me) {
        int tree = fa[me], cjr = fa[tree], op = opp(me), ls = ch[me][op ^ 1];
        fa[ls] = tree;
        ch[tree][op] = ls;
        ch[me][op ^ 1] = tree;
        if (cjr)
            ch[cjr][opp(tree)] = me;
        fa[tree] = me;
        fa[me] = cjr;
    }
    inline void splay(int tree) {
        while (fa[tree]) {
            int cjr = fa[tree];
            if (fa[cjr])
                xuan((opp(tree) == opp(cjr)) ? cjr : tree);
            xuan(tree);
        }
    }
    void insert_s(int &tree, int me) {
        if (!tree) {
            tree = me;
            return;
        }
        insert_s(ch[tree][data[tree] < data[me]], me);
        fa[ch[tree][data[tree] < data[me]]] = tree;
    }
    inline void insert(node dat) {
        int me = gn;
        gn++;
        data[me] = dat;
        insert_s(root, me);
        splay(me);
        root = me;
    }
    int find(int tree, node dat) {
        if (dat.k == data[tree].k && dat.b == data[tree].b) {
            return (tree);
        }
        return (find(ch[tree][data[tree] < dat], dat));
    }
    int getmx(int tree) {
        while (ch[tree][1]) tree = ch[tree][1];
        return (tree);
    }
    inline void del(node dat) {
        int me = find(root, dat);
        splay(me);
        int ls = ch[me][0], rs = ch[me][1];
        fa[ls] = 0;
        fa[rs] = 0;
        if (!ls) {
            root = rs;
            return;
        }
        ls = getmx(ls);
        splay(ls);
        fa[rs] = ls;
        ch[ls][1] = rs;
        root = ls;
    }
    double x[100001], y[100001];
    typedef struct _b_t {
        int s;
        int t;
        int id;
        friend bool operator<(const _b_t &a, const _b_t &b) {
            return (atan2(y[a.t] - y[a.s], x[a.t] - x[a.s]) < atan2(y[b.t] - y[b.s], x[b.t] - x[b.s]));
        }
    } bian_t;
    vector<bian_t> vec[100001];
    int vid[200001];
    int anss[200001];
    typedef struct _pt {
        double x;
        double y;
        unsigned char gj;
        int id;
        friend bool operator<(const _pt &a, const _pt &b) {
            if (a.x != b.x)
                return (a.x < b.x);
            return (a.gj > b.gj);
        }
    } pt;
    pt pts[1000001];
    int val[100001], bel[200001], ss[200001], ts[200001];
    inline double cross(double x1, double y1, double x2, double y2) { return (x1 * y2 - x2 * y1); }
    int getnxt(int tree, double y) {
        if (!tree)
            return (0);
        if (data[tree].k * dx + data[tree].b > y) {
            int cjr = getnxt(ch[tree][0], y);
            if (cjr)
                return (cjr);
            return (tree);
        }
        return (getnxt(ch[tree][1], y));
    }
    void ywymain() {
        tree::deep[0] = -1;
        int n = get(), m = get();
        for (register int i = 1; i <= n; i++) x[i] = get(), y[i] = get(), ints[i] = i;
        for (register int i = 1; i <= m; i++) {
            int s = get(), t = get(), l = get();
            val[i] = l;
            bian_t cjr;
            cjr.s = s;
            cjr.t = t;
            cjr.id = i;
            vec[s].push_back(cjr);
            cjr.s = t;
            cjr.t = s;
            cjr.id = i + m;
            vec[t].push_back(cjr);
            ss[i] = s;
            ts[i] = t;
            ss[i + m] = t;
            ts[i + m] = s;
        }
        for (register int i = 1; i <= n; i++) sort(vec[i].begin(), vec[i].end());
        for (register int i = 1; i <= n; i++) {
            for (register int j = 0; j < vec[i].size(); j++) vid[vec[i][j].id] = j;
        }
        int gpt = 1;
        int rt = 0;
        for (register int i = 1; i <= m * 2; i++) {
            if (bel[i])
                continue;
            int me = gpt;
            gpt++;
            double s = 0;
            int cur = i;
            do {
                s += cross(x[ts[cur]] - x[ss[cur]], y[ts[cur]] - y[ss[cur]], x[ts[cur]], y[ts[cur]]);
                bel[cur] = me;
                cur = vec[ts[cur]][(vid[(cur > m) ? (cur - m) : (cur + m)] + vec[ts[cur]].size() - 1) %
                                   vec[ts[cur]].size()]
                          .id;
            } while (cur != i);
            if (s >= 0)
                rt = me;
        }
        int ptr = 1;
        for (register int i = 1; i <= m; i++) {
            if (bel[i] == rt || bel[i + m] == rt)
                continue;
            bians[ptr].s = bel[i];
            bians[ptr].t = bel[i + m];
            bians[ptr].l = val[i];
            ptr++;
        }
        sort(bians + 1, bians + ptr);
        for (register int i = 1; i < ptr; i++) {
            int aa = find(bians[i].s), ab = find(bians[i].t);
            if (aa == ab)
                continue;
            ints[aa] = ab;
            tree::add(bians[i].s, bians[i].t, bians[i].l);
            tree::add(bians[i].t, bians[i].s, bians[i].l);
        }
        for (register int i = 1; i < gpt; i++)
            if (ints[i] == i)
                tree::dfs(i, 0);
        for (register int i = 1; i <= 16; i++) {
            for (register int j = 1; j < gpt; j++) {
                tree::ance[j][i] = tree::ance[tree::ance[j][i - 1]][i - 1];
                tree::mx[j][i] = max(tree::mx[j][i - 1], tree::mx[tree::ance[j][i - 1]][i - 1]);
            }
        }
        ptr = 1;
        for (register int i = 1; i <= n; i++) {
            pts[ptr].x = x[i];
            pts[ptr].y = y[i];
            pts[ptr].id = i;
            pts[ptr].gj = 1;
            ptr++;
        }
        int q = get();
        for (register int i = 1; i <= q; i++) {
            double x1, y1, x2, y2;
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            pts[ptr].x = x1;
            pts[ptr].y = y1;
            pts[ptr].gj = 0;
            pts[ptr].id = i;
            ptr++;
            pts[ptr].x = x2;
            pts[ptr].y = y2;
            pts[ptr].gj = 0;
            pts[ptr].id = i + q;
            ptr++;
        }
        sort(pts + 1, pts + ptr);
        for (register int i = 1; i < ptr;) {
            int cjr = i;
            while (cjr < ptr && pts[cjr].x == pts[i].x) cjr++;
            for (register int j = i; j < cjr; j++) {
                if (!pts[j].gj)
                    break;
                for (register int k = 0; k < vec[pts[j].id].size(); k++) {
                    bian_t tmp = vec[pts[j].id][k];
                    if (x[tmp.t] >= x[tmp.s])
                        continue;
                    dx = pts[i].x - 0.00001;
                    node t;
                    t.k = (y[tmp.t] - y[tmp.s]) / (x[tmp.t] - x[tmp.s]);
                    t.b = y[tmp.t] - x[tmp.t] * t.k;
                    t.id = bel[tmp.id];
                    del(t);
                }
            }
            for (register int j = i; j < cjr; j++) {
                if (!pts[j].gj)
                    break;
                for (register int k = 0; k < vec[pts[j].id].size(); k++) {
                    bian_t tmp = vec[pts[j].id][k];
                    if (x[tmp.t] <= x[tmp.s])
                        continue;
                    dx = pts[i].x + 0.00001;
                    node t;
                    t.k = (y[tmp.s] - y[tmp.t]) / (x[tmp.s] - x[tmp.t]);
                    t.b = y[tmp.s] - x[tmp.s] * t.k;
                    t.id = bel[(tmp.id > m) ? (tmp.id - m) : (tmp.id + m)];
                    insert(t);
                }
            }
            for (register int j = i; j <= cjr; j++) {
                if (pts[j].gj)
                    continue;
                dx = pts[j].x + 0.00001;
                int nx = getnxt(root, pts[j].y);
                if (!nx) {
                    anss[pts[j].id] = rt;
                    continue;
                }
                anss[pts[j].id] = data[nx].id;
            }
            i = cjr;
        }
        for (register int i = 1; i <= q; i++) {
            int s = anss[i], t = anss[i + q];
            if (find(s) != find(t)) {
                printf("-1\n");
                continue;
            }
            if (s == rt && t == rt) {
                printf("-1\n");
                continue;
            }
            printf("%d\n", tree::lca(s, t));
        }
    }
}
int main() {
    ywy::ywymain();
    return (0);
}