bzoj4449: [Neerc2015]Distance on 點分治 三角剖分 平面圖與對偶圖
阿新 • • 發佈:2018-11-06
bzoj4449: [Neerc2015]Distance on Triangulation
Description
給定一個凸n邊形,以及它的三角剖分。再給定q個詢問,每個詢問是一對凸多邊行上的頂點(a,b),問點a最少經過多少條邊(可以是多邊形上的邊,也可以是剖分上的邊)可以到達點b。
Input**
第一行一個整數n(n <= 50000),代表有n個點。點1,2,3,…,n是凸多邊形上是順時針排布的。
接下來n-3行,每行兩個整數(x,y),代表(x,y)之間有一條剖分邊。
接下來是一個整數q(q <= 100000),代表有q組詢問。
接下來q行是兩個整數(a,b)。
Output**
輸出q行,每行一個整數代表最少邊數。
Sample Input**
6
1 5
2 4
5 2
5
1 3
2 5
3 4
6 3
6 6
Sample Output
2
1
1
3
0
分析
平面圖與對偶圖的轉化-連結
三角剖分的對偶圖是一棵樹。
考慮到對偶圖中的環和割是一一對應的。
說白了就是把其中一個三角形刪了,必定會把平面圖分成兩塊。這兩塊不聯通。
所以這分屬兩塊的詢問點必定經過這個三角形中的某一個節點。
也就是說可以單獨考慮過對偶圖上的經過某個三角形的路徑。上點分治即可。
每次Dfs處理出所有當前塊內的點,然後Bfs求到三個點的距離,如果兩個點分屬兩個不同的塊,直接採用這次的答案,否則遞迴求解。
複雜度
程式碼
常數巨大。
#include<bits/stdc++.h>
const int N = 2e6 + 10;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
struct Edge {
int pr[N], nx[N], to[N], tp;
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp;}
void adds(int u, int v) {add(u, v); add(v, u);}
}G, T, Q;
struct E {int x, y, z;}e[N];
bool cmp(E a, E b) {return a.x == b.x ? a.y < b.y : a.x < b.x;}
int p[N][3], D[3][N], sz[N], d[N], q[N], st[N], mk[N], bmk[N];
int be[N], qu[N], qv[N], ans[N], tm, btm, sums, mn, Rt, m, n, cnt; bool vis[N], in[N];
void Ins(int x, int y, int z) {e[++m] = (E){x, y, z};}
void Ins(int x, int id) {
for(int i = 0;i < 3 && x; ++i)
if(x > p[id][i]) std::swap(p[id][i], x);
if(p[id][2]) {
Ins(p[id][0], p[id][1], id);
Ins(p[id][0], p[id][2], id);
Ins(p[id][1], p[id][2], id);
}
}
void Build() {
int L = 1, R = 0;
for(int i = 1;i <= n; ++i) if(d[i] == 2) q[++R] = i; cnt = 0;
for(int u = q[L];L <= R; u = q[++L])
if(d[u] == 2) {
Ins(u, ++cnt); in[u] = true;
for(int i = G.pr[u]; i; i = G.nx[i]) {
if((--d[G.to[i]]) == 2) q[++R] = G.to[i];
if(!in[G.to[i]]) Ins(G.to[i], cnt);
}
}
std::sort(e + 1, e + m + 1, cmp);
for(int i = 1;i < m; ++i)
if(e[i].x == e[i + 1].x && e[i].y == e[i + 1].y)
T.adds(e[i].z, e[i + 1].z);
}
void G_get(int u, int fa) {
sz[u] = 1; int tp = 0;
for(int i = T.pr[u], v; i; i = T.nx[i])
if(!vis[v = T.to[i]] && v != fa)
G_get(v, u), tp = std::max(tp, sz[v]), sz[u] += sz[v];
tp = std::max(tp, sums - sz[u]);
if(tp < mn) mn = tp, Rt = u;
}
void Bfs(int x, int *D) {
int L = 1, R; q[R = 1] = x; D[x] = 0; bmk[x] = ++btm;
for(int u = q[L];L <= R; u = q[++L])
for(int i = G.pr[u], v; i; i = G.nx[i])
if(mk[v = G.to[i]] == tm && bmk[v] != btm)
bmk[v] = btm, q[++R] = v, D[v] = D[u] + 1;
}
void Dfs(int u, int fa, int rt) {
for(int k = 0;k < 3; ++k)
mk[p[u][k]] = tm, be[p[u][k]] = rt;
for(int i = T.pr[u]; i; i = T.nx[i])
if(T.to[i] != fa && !vis[T.to[i]])
Dfs(T.to[i], u, rt);
}
void Work(int x, int cs) {
if(!Q.pr[x]) return ;
mn = 1e9; sums = cs; G_get(x, 0); vis[Rt] = true; ++tm;
for(int j = T.pr[Rt]; j; j = T.nx[j])
if(!vis[T.to[j]])
Dfs(T.to[j], 0, T.to[j]);
for(int k = 0;k < 3; ++k)
mk[p[Rt][k]] = tm, be[p[Rt][k]] = Rt;
for(int k = 0;k < 3; ++k)
Bfs(p[Rt][k], D[k]);
int tp = 0; for(int i = Q.pr[x]; i; i = Q.nx[i]) st[++tp] = Q.to[i]; Q.pr[x] = 0;
for(int i = 1;i <= tp; ++i) {
int nw = st[i], u = qu[st[i]], v = qv[st[i]];
if(be[u] == be[v]) {
if(be[u] == Rt) ans[nw] = 1;
else Q.add(be[u], nw);
}
else {
int r = 1e9;
for(int k = 0;k < 3; ++k)
r = std::min(r, D[k][u] + D[k][v]);
ans[nw] = r;
}
}
for(int i = T.pr[Rt]; i; i = T.nx[i])
if(!vis[T.to[i]])
Work(T.to[i], sz[T.to[i]] > sz[Rt] ? cs - sz[Rt] : sz[T.to[i]]);
}
int main() {
n = ri();
for(int i = 1;i <= n; ++i) G.adds(i, i % n + 1), d[i] = 2;
for(int i = 1, x, y;i <= n - 3; ++i) x = ri(), y = ri(), ++d[x], ++d[y], G.adds(x, y);
Build(); int q = ri();
for(int i = 1;i <= q; ++i) {
qu[i] = ri(), qv[i] = ri();
if(qu[i] != qv[i]) Q.add(1, i);
}
Work(1, cnt);
for(int i = 1;i <= q; ++i) printf("%d\n", ans[i]);
return 0;
}