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;
}
posted @ 2022-09-28 09:45  azzc  阅读(62)  评论(0)    收藏  举报