平面图转对偶图
将每条无向边拆成两条有向边。对于一个平面,我们通过其接壤的所有有向边来寻找它。
假定我们逆时针方向行走每条边来找平面。具体的,对于一个点 \(u\),若从点 \(v\) 走到了 \(u\),那么下一个点 \(w\) 应满足:有向边 \((u, w)\) 在 \((u, v)\) 逆时针方向最近。
所以可以对 \(u\) 的所有出边按极角排序,求向量的极角可以利用函数 atan2(y, x)。边可以成对储存以方便处理编号,对于编号为 \(i\) 的边可以求得其下一条需要走的边 \(nxt_i\)。
然后随便枚举一条边 \(i\) 开始走,不断跳 \(nxt_i\) 即可。对于最外层无限大的平面,利用叉积算出来其面积为负数,可以据此找到这个面的编号。
先找到所有平面,如果可以找到两个点所在的平面编号,剩下直接一个 kruskal 重构树就搞定了。
现在的问题是求若干个点分别所在平面编号。考虑按 x 扫面线,维护包含当前 x 的所有边(线段),显然可以快速判断他们的高低关系,每次查询一个点处于哪两条边之间。Treap 维护即可。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
template <class T>
const inline void rd(T &x) {
char ch; bool neg = 0;
while(!isdigit(ch = getchar()))
if(ch == '-') neg = 1;
x = ch - '0';
while(isdigit(ch = getchar()))
x = (x << 1) + (x << 3) + ch - '0';
if(neg) x = -x;
}
const ll maxn = 2e5 + 10, inf = 1e9, mod = 998244353;
ll power(ll a, ll b = mod - 2, ll p = mod) {
ll s = 1;
while(b) {
if(b & 1) s = 1ll * s * a % p;
a = 1ll * a * a % p, b >>= 1;
} return s;
}
template <class T, class _T>
const inline ll pls(const T x, const _T y) { return x + y >= mod? x + y - mod : x + y; }
template <class T, class _T>
const inline void add(T &x, const _T y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T, class _T>
const inline void chkmax(T &x, const _T y) { x = x < y? y : x; }
template <class T, class _T>
const inline void chkmin(T &x, const _T y) { x = x < y? x : y; }
ll n, m, q, x[maxn], y[maxn], nxt[maxn], id[maxn], cnt, tot = 1;
vector <ll> to[maxn]; ll emp; vector <ll> arr;
struct edge { ll u, v; double d; } e[maxn];
long long Cro(ll i, ll j) { return 1ll * x[i] * y[j] - 1ll * x[j] * y[i]; }
void link(ll u, ll v) {
e[++tot] = (edge) {u, v, atan2(y[v] - y[u], x[v] - x[u])};
to[u].pb(tot);
}
struct Data { double x, y; ll *ans; } Q[maxn]; ll pos[maxn];
mt19937 rnd(20090623); ll rt;
bool Comp(ll i, ll j) {
if(x[e[i].u] == x[e[j].u]) {
if(y[e[i].u] != y[e[j].u]) return y[e[i].u] > y[e[j].u];
return 1ll * (x[e[j].v] - x[e[j].u]) * (y[e[i].v] - y[e[i].u])
> 1ll * (y[e[j].v] - y[e[j].u]) * (x[e[i].v] - x[e[i].u]);
}
if(x[e[i].u] < x[e[j].u]) {
ll a = x[e[i].v] - x[e[i].u], b = y[e[i].v] - y[e[i].u];
ll c = x[e[j].u] - x[e[i].u], d = y[e[j].u] - y[e[i].u];
return 1ll * a * d < 1ll * b * c;
} else {
ll a = x[e[j].v] - x[e[j].u], b = y[e[j].v] - y[e[j].u];
ll c = x[e[i].u] - x[e[j].u], d = y[e[i].u] - y[e[j].u];
return 1ll * a * d > 1ll * b * c;
}
}
struct Treap {
ll tot, lc[maxn], rc[maxn], h[maxn], rp[maxn];
void split(ll p, ll k, ll &s1, ll &s2) {
if(!p) return s1 = s2 = 0, void();
if(h[p] != k && Comp(h[p], k)) split(lc[p], k, s1, lc[s2 = p]);
else split(rc[p], k, rc[s1 = p], s2);
}
void split_last(ll p, ll &s) {
if(rc[p]) split_last(rc[p], rc[s = p]);
else s = lc[p], lc[p] = 0;
}
ll merge(ll p, ll q) {
if(!p || !q) return p | q;
if(rp[p] > rp[q]) return rc[p] = merge(rc[p], q), p;
else return lc[q] = merge(p, lc[q]), q;
}
void insert(ll k) {
ll s1, s2; split(rt, k, s1, s2);
++tot, h[tot] = k, rp[tot] = rnd();
rt = merge(merge(s1, tot), s2);
}
void erase(ll k) {
ll s1, s2;
split(rt, k, s1, s2);
ll q = s1;
while(rc[q]) q = rc[q];
assert(h[q] == k);
split_last(s1, s1);
rt = merge(s1, s2);
}
ll query(double x0, double y0) {
ll p = rt, k = emp;
while(p) {
ll a = x[e[h[p]].v] - x[e[h[p]].u];
ll b = y[e[h[p]].v] - y[e[h[p]].u];
double c = x0 - x[e[h[p]].u];
double d = y0 - y[e[h[p]].u];
if(a * d - b * c > 0) k = id[h[p]], p = rc[p];
else p = lc[p];
} return k;
}
} tr;
ll fa[maxn][20], d[maxn], eid[maxn], W[maxn];
ll dep[maxn], lc[maxn], rc[maxn], val[maxn];
ll find(ll x) { return d[x] ^ x? d[x] = find(d[x]) : x; }
void dfs(ll u) {
for(ll i = 1; i < 20; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
if(!lc[u]) return;
fa[lc[u]][0] = fa[rc[u]][0] = u;
dep[lc[u]] = dep[rc[u]] = dep[u] + 1;
dfs(lc[u]), dfs(rc[u]);
}
ll lca(ll u, ll v) {
if(dep[u] < dep[v]) swap(u, v);
ll d = dep[u] - dep[v];
for(ll i = 0; i < 20; i++)
if(d & (1 << i)) u = fa[u][i];
if(u == v) return u;
for(ll i = 19; ~i; i--)
if(fa[u][i] ^ fa[v][i])
u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int main() {
rd(n), rd(m);
for(ll i = 1; i <= n; i++) rd(x[i]), rd(y[i]), arr.pb(i);
for(ll i = 1; i <= m; i++) {
ll u, v, w; rd(u), rd(v), rd(w);
link(u, v), link(v, u), eid[i] = i, W[i] = w;
}
for(ll u = 1; u <= n; u++) {
sort(to[u].begin(), to[u].end(), [](ll i, ll j) {
return e[i].d < e[j].d;
});
for(ll i = 0; i < to[u].size(); i++)
nxt[to[u][(i + 1) % to[u].size()] ^ 1] = to[u][i];
}
for(ll i = 2; i <= tot; i++) {
if(id[i]) continue; id[i] = ++cnt, d[cnt] = cnt;
long long s = Cro(e[i].u, e[i].v);
for(ll j = nxt[i]; j ^ i; j = nxt[j])
id[j] = cnt, s += Cro(e[j].u, e[j].v);
if(s <= 0) emp = cnt;
} rd(q);
sort(arr.begin(), arr.end(), [](ll i, ll j) { return x[i] < x[j]; });
for(ll i = 1; i <= q; i++) {
scanf("%lf%lf%lf%lf", &Q[i].x, &Q[i].y, &Q[i + q].x, &Q[i + q].y);
Q[i].ans = &pos[i], Q[i + q].ans = &pos[i + q];
pos[i] = pos[i + q] = emp;
}
sort(Q + 1, Q + 1 + 2 * q, [](const Data A, const Data B) {
return A.x < B.x;
});
for(ll i = 0, j = 0; i < n; i++) {
ll u = arr[i];
while(j < 2 * q && Q[j + 1].x <= x[u])
++j, *Q[j].ans = tr.query(Q[j].x, Q[j].y);
ll _i = i;
while(_i + 1 < n && x[arr[_i + 1]] == x[u]) ++_i;
for(ll _ = i; _ <= _i; _++) {
u = arr[_];
for(ll k: to[u])
if(x[e[k].v] < x[u]) tr.erase(k ^ 1);
}
for(ll _ = i; _ <= _i; _++) {
u = arr[_];
for(ll k: to[u])
if(x[e[k].v] > x[u]) tr.insert(k);
} i = _i;
}
sort(eid + 1, eid + 1 + m, [](ll i, ll j) { return W[i] < W[j]; });
for(ll i = 1; i <= m; i++) {
ll k = eid[i];
ll u = find(id[k << 1]), v = find(id[k << 1|1]);
if(u == emp || v == emp) continue;
if(u ^ v) {
++cnt, d[u] = d[v] = d[cnt] = cnt;
lc[cnt] = u, rc[cnt] = v, val[cnt] = W[k];
}
}
for(ll i = 1; i <= cnt; i++)
if(d[i] == i) dep[i] = 1, dfs(i);
for(ll i = 1; i <= q; i++) {
ll u = pos[i], v = pos[i + q];
if(u == emp || v == emp || find(u) ^ find(v)) puts("-1");
else printf("%lld\n", val[lca(u, v)]);
}
return 0;
}

浙公网安备 33010602011771号