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求到三个点的距离,如果两个点分属两个不同的块,直接采用这次的答案,否则递归求解。
复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
代码
常数巨大。
#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;
}