您的位置:首页 > 其它

[NEERC 2015] bzoj4449 Distance on Triangulation [分治+最短路]

2018-03-25 21:15 465 查看
Description:

给定一个凸nn边形,以及它的三角剖分。再给定qq个询问,每个询问是一对凸多边行上的顶点(a,b)(a,b),问点aa最少经过多少条边(可以是多边形上的边,也可以是剖分上的边)可以到达点bb。

Solution:

看起来很难写,其实想清楚还是比较好写的。

我们可以对每个多边形进行分治,每次选择其中的一个分的最均匀的对角线,以其两个顶点做最短路,并更新跨过这条对角线的所有询问,这些询问取到最小值肯定也是经过这条对角线。这样分治只需要nlognnlogn的时间可以解决所有询问。分治时要记录当前多边形中的对角线,点,还有询问,求最短路时只要把当前区间里的点求最短路,否则时间复杂度不对。点则是为了在求最短路和分治区间时判断是否属于当前区间。

代码几乎是抄的,主要是结构。

分治主要思想是把一些有相同点的问题通过预处理批量处理,比如这里就是经过对角线的询问,先预处理出两点的最短路,复杂度很低,然后其他的就可以批量预处理了。

cdq分治也是,找出一些操作,其中一部分都受到另一部分影响,所以把前一部分通过数据结构预处理,这样就不用两两重复操作了。

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5, inf = 1e9;
struct data {
int l, r, id;
} q
, E
, tmp1
, tmp2
, tmp3
, tmp4
;
int n, m;
int ans
, B
, d1
, d2
, tmp5
, tmp6
;
vector<int> G
;
queue<int> que;
int check(int l, int r, int x) {
return lower_bound(B + l, B + r + 1, x) - B;
}
void bfs(int l, int r, int s, int *d) {
for(int i = l; i <= r; ++i) {
d[B[i]] = inf;
}
d[s] = 0;
que.push(s);
while(!que.empty()) {
int u = que.front();
que.pop();
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(d[v] == inf && B[check(l, r, v)] == v) {
d[v] = d[u] + 1;
que.push(v);
}
}
}
}
int get_ans(int u, int v) {
return min(min(d1[u] + d1[v], d2[u] + d2[v]), min(d1[u] + 1 + d2[v], d1[v] + 1 + d2[u]));
}
void cdq(int l, int r, int x, int y, int a, int b) {
if(l > r || x > y) {
return;
}
int mn = inf, pos;
for(int i = l; i <= r; ++i) {
int p = check(x, y, E[i].l), q = check(x, y, E[i].r);
if(p > q) {
swap(p, q);
}
int tmp = max(q - p + 1, y - x + 1 - q + p);
if(tmp < mn) {
mn = tmp;
pos = i;
}
}
int L = E[pos].l, R = E[pos].r, tot1 = 0, tot2 = 0, tot3 = 0, tot4 = 0, tot5 = 0, tot6 = 0;
bfs(x, y, L, d1);
bfs(x, y, R, d2);
for(int i = a; i <= b; ++i) {
if(q[i].l == L && q[i].r == R) {
ans[q[i].id] = 1;
continue;
}
ans[q[i].id] = min(ans[q[i].id], get_ans(q[i].l, q[i].r));
if(q[i].l > L && q[i].r < R) {
tmp1[++tot1] = q[i];
} else if((q[i].l > R && q[i].r > R) || (q[i].l < L && q[i].r > R) || (q[i].r < L)) {
tmp2[++tot2] = q[i];
}
}
for(int i = 1; i <= tot1; ++i) {
q[a + i - 1] = tmp1[i];
}
for(int i = 1; i <= tot2; ++i) {
q[a + tot1 + i - 1] = tmp2[i];
}
for(int i = l; i <= r; ++i) {
if(i != pos) {
if(E[i].l >= L && E[i].r <= R) {
tmp3[++tot3] = E[i];
} else {
tmp4[++tot4] = E[i];
}
}
}
for(int i = 1; i <= tot3; ++i) {
E[l + i - 1] = tmp3[i];
}
for(int i = 1; i <= tot4; ++i) {
E[l + tot3 + i - 1] = tmp4[i];
}
for(int i = x; i <= y; ++i) {
if(B[i] >= L && B[i] <= R) {
tmp5[++tot5] = B[i];
} else {
tmp6[++tot6] = B[i];
}
}
for(int i = 1; i <= tot5; ++i) {
B[x + i - 1] = tmp5[i];
}
for(int i = 1; i <= tot6; ++i) {
B[x + tot5 + i - 1] = tmp6[i];
}
cdq(l, l + tot3 - 1, x, x + tot5 - 1, a, a + tot1 - 1);
cdq(l + tot3, l + tot3 + tot4 - 1, x + tot5, x + tot5 + tot6 - 1, a + tot1, a + tot1 + tot2 - 1);
}
int main() {
//  freopen("distance.in", "r", stdin);
//  freopen("distance.out", "w", stdout);
scanf("%d", &n);
for(int i = 1; i <= n - 3; ++i) {
int u, v;
scanf("%d%d", &u, &v);
if(u > v) {
swap(u, v);
}
G[u].push_back(v);
G[v].push_back(u);
E[i].l = u;
E[i].r = v;
}
for(int i = 1; i <= n; ++i) {
B[i] = i;
G[i].push_back(i % n + 1);
G[i % n + 1].push_back(i);
}
scanf("%d", &m);
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &q[i].l, &q[i].r);
q[i].id = i;
if(q[i].l > q[i].r) {
swap(q[i].l, q[i].r);
}
ans[i] = min(q[i].r - q[i].l, n + q[i].l - q[i].r);
}
cdq(1, n - 3, 1, n, 1, m);
for(int i = 1; i <= m; ++i) {
printf("%d\n", ans[i]);
}
//  fclose(stdin);
//  fclose(stdout);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: