BZOJ2104. Wc2009 shortest最短路问题
BZOJ2104. Wc2009 shortest
P4150 [WC2009]最短路问题
一条路线至多掉头4次(因为方格的高为6)
普遍情况:(所有情况均为左边0/2/4次拐弯
左边 右边 和右边0/2/4次拐弯构成)
s-+ +-e 当左边三个与y1的交点
| | 和右边三个与y2的交点重合时
+-i-+ +-l-+ 就成为了退化的情况
| |
+-j-----k-+
^y1 ^y2
每个区间维护三个信息: ll[i][j],rr[i][j],lr[i][j]
分别表示在这个区间内
从左端点的i到左端点的j,不超出这个区间的最短路长度
从左端点的i到右端点的j,不超出这个区间的最短路长度
从右端点的i到右端点的j,不超出这个区间的最短路长度
每次询问: 求出区间 l=[1,y1],m=[y1,y2],r=[y2,n]
枚举i,j,k,h,求出以下的最小值:
m.ll[x1][i]+l.rr[i][j]+m.lr[j][k]+r.ll[k][h]+m.rr[h][x2]
-m.ll[i][i]-m.ll[j][j]-m.rr[k][k]-m.rr[h][h] (去重)
合并两个区间 l 和 r:
用lm表示从l到m,再在右边绕一圈回到m的最短路
用rm表示从r到m+1,再在左边绕一圈回到m+1的最短路
lm[i][j]=min{l.lr[i][k]+r.ll[k][j]+l.rr[j][j]}
rm[i][j]=min{r.lr[k][j]+l.rr[i][k]+r.ll[i][i]}
最终的ll[i][j]=min{l.ll[i][j], lm[i][k]+l.lr[j][k]-l.rr[k][k]}
最终的rr[i][j]=min{r.rr[i][j], rm[k][i]+r.lr[k][j]-r.ll[k][k]}
最终的lr[i][j]=min{lm[i][k]+rm[k][j]-l.rr[k][k]-r.ll[k][k], l.lr[i][k]+r.lr[k][j]}
点击查看代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
typedef long long LL;
int n, q, a[6][N], sum[6];
LL lm[6][6], rm[6][6];
struct Node {
LL ll[6][6], rr[6][6], lr[6][6];
} tr[N << 2];
inline int ls(int u) { return u << 1; }
inline int rs(int u) { return u << 1 | 1; }
// 合并两个区间 (有点问题)
Node merge(const Node &l, const Node &r) {
static Node tmp;
memset(lm, 0x3f, sizeof(lm)), memset(rm, 0x3f, sizeof(rm));
memset(tmp.ll, 0x3f, sizeof(tmp.ll)), memset(tmp.rr, 0x3f, sizeof(tmp.rr));
// memcpy(tmp.ll, l.ll, sizeof(l.ll)), memcpy(tmp.rr, r.rr, sizeof(r.rr));
memset(tmp.lr, 0x3f, sizeof(tmp.lr));
for(int i = 0; i < 6; i ++)
for(int j = 0; j < 6; j ++) {
lm[i][j] = l.lr[i][j], rm[i][j] = r.lr[j][i];
for(int k = 0; k < 6; k ++)
lm[i][j] = min(lm[i][j], l.lr[i][k] + r.ll[k][j]),
rm[i][j] = min(rm[i][j], r.lr[k][i] + l.rr[k][j]);
}
for(int i = 0; i < 6; i ++)
for(int j = 0; j < 6; j ++) {
tmp.ll[i][j] = l.ll[i][j], tmp.rr[i][j] = r.rr[i][j];
for(int k = 0; k < 6; k ++)
tmp.ll[i][j] = min(tmp.ll[i][j], lm[i][k] + l.lr[j][k]),
tmp.rr[i][j] = min(tmp.rr[i][j], rm[i][k] + r.lr[k][j]),
tmp.lr[i][j] = min(tmp.lr[i][j], lm[i][k] + rm[j][k]);
}
// for(int i = 0; i < 6; i ++)
// for(int j = 0; j < 6; j ++) {
// for(int k = 0; k < 6; k ++)
// lm[i][j] = min(lm[i][j], l.lr[i][k] + r.ll[k][j] + l.rr[j][j]),
// rm[i][j] = min(rm[i][j], r.lr[k][j] + l.rr[i][j] + r.ll[i][i]);
// }
// for(int i = 0; i < 6; i ++)
// for(int j = 0; j < 6; j ++)
// for(int k = 0; k < 6; k ++)
// tmp.ll[i][j] = min(tmp.ll[i][j], lm[i][k] + l.lr[j][k] - l.rr[k][k]),
// tmp.rr[i][j] = min(tmp.rr[i][j], rm[k][i] + r.lr[k][j] - r.ll[k][k]),
// tmp.lr[i][j] = min(tmp.lr[i][j], min(lm[i][k] + rm[k][j] - l.rr[k][k] - r.ll[k][k], l.lr[i][k] + r.lr[k][j]));
return tmp;
}
void build(int u, int l, int r) {
if(l == r) { // 初始值: 最短路为中间的点的权值
for(int i = 0; i < 6; i ++) sum[i] = a[i][l] + (i ? sum[i - 1] : 0);
for(int i = 0; i < 6; i ++)
for(int j = i; j < 6; j ++)
tr[u].ll[i][j] = tr[u].rr[i][j] = tr[u].lr[i][j] =
tr[u].ll[j][i] = tr[u].rr[j][i] = tr[u].lr[j][i] = sum[j] - (i ? sum[i - 1] : 0);
} else {
int mid = (l + r) >> 1;
build(ls(u), l, mid);
build(rs(u), mid + 1, r);
tr[u] = merge(tr[ls(u)], tr[rs(u)]);
}
}
void modify(int u, int l, int r, int x, int y, int z) {
if(l == r) {
a[x][y] = z;
for(int i = 0; i < 6; i ++) sum[i] = a[i][y] + (i ? sum[i - 1] : 0);
for(int i = 0; i < 6; i ++)
for(int j = i; j < 6; j ++)
tr[u].ll[i][j] = tr[u].rr[i][j] = tr[u].lr[i][j] =
tr[u].ll[j][i] = tr[u].rr[j][i] = tr[u].lr[j][i] = sum[j] - (i ? sum[i - 1] : 0);
} else {
int mid = (l + r) >> 1;
if(y <= mid) modify(ls(u), l, mid, x, y, z);
else modify(rs(u), mid + 1, r, x, y, z);
tr[u] = merge(tr[ls(u)], tr[rs(u)]);
}
}
Node query(int u, int l, int r, int y1, int y2) {
if(y1 <= l && r <= y2) return tr[u];
else {
int mid = (l + r) >> 1;
if(y1 <= mid) {
if(y2 > mid) return merge(query(ls(u), l, mid, y1, y2), query(rs(u), mid + 1, r, y1, y2));
else return query(ls(u), l, mid, y1, y2);
} else return query(rs(u), mid + 1, r, y1, y2);
}
}
int main() {
scanf("%d", &n);
for(int x = 0; x < 6; x ++)
for(int y = 1; y <= n; y ++) scanf("%d", a[x] + y);
build(1, 1, n);
scanf("%d", &q);
for(int t = 1, op, x1, y1, x2, y2, c; t <= q; t ++) {
scanf("%d%d%d", &op, &x1, &y1), x1 --;
if(op == 1) scanf("%d", &c), modify(1, 1, n, x1, y1, c);
else {
scanf("%d%d", &x2, &y2), x2 --;
if(y1 > y2) swap(x1, x2), swap(y1, y2);
static Node l, m, r;
l = query(1, 1, n, 1, y1);
m = query(1, 1, n, y1, y2);
r = query(1, 1, n, y2, n);
LL ans = 0x3f3f3f3f3f3f3f3fLL;
for(int i = 0; i < 6; i ++)
for(int j = 0; j < 6; j ++)
for(int k = 0; k < 6; k ++)
for(int h = 0; h < 6; h ++)
ans = min(ans, m.ll[x1][i] + l.rr[i][j] + m.lr[j][k] + r.ll[k][h] + m.rr[h][x2] - m.ll[i][i] - m.ll[j][j] - m.rr[k][k] - m.rr[h][h]);
printf("%lld\n", ans);
}
}
return 0;
}
浙公网安备 33010602011771号