【数据结构 线段树 动态规划 动态dp】JZOJ_6293 迷宫

本文介绍了一种结合线段树和矩阵乘法的算法,用于解决矩阵中带墙的最短路径问题。通过维护矩阵的行状态,实现高效的路径更新和查询。代码示例展示了具体实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

给出一个矩阵,里面有些墙,有两种操作:
1、改变矩阵的一个点的状态(有墙->无墙)(无墙->有墙)
2、询问一个点到另一个点的最短路

思路

利用线段树维护 f x , y f_{x,y} fx,y代表当前区间最左端的第 x x x行到最右端的第 y y y行。
两个线段树合并时 f x , y = f x , k + f k , y + 1 f_{x,y}=f_{x,k}+f_{k,y}+1 fx,y=fx,k+fk,y+1,可看做成一个广义的矩阵乘法,然后就这样了。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

const int inf = 707406378;

struct matrix {
	int a[6][6];
};
struct SegmentTree {
	int l, r;
	matrix dat;
}t[800001];
int n, m, q;
int a[6][200001];

matrix operator *(const matrix &a, const matrix &b) {
	matrix c;
	memset(c.a, 127 / 3, sizeof(c.a));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			for (int k = 1; k <= n; k++)
				c.a[i][j] = std::min(c.a[i][j], a.a[i][k] + b.a[k][j] + 1);
	return c; 
}

void init(SegmentTree &tmp, int pos) {
	memset(tmp.dat.a, 127 / 3, sizeof(tmp.dat.a));
	for (int i = 1; i <= n; i++) {
		if (a[i][pos]) tmp.dat.a[i][i] = 0;
		for (int j = i - 1; j >= 1; j--)
			if (a[j][pos] && tmp.dat.a[i][j + 1] < inf) tmp.dat.a[i][j] = tmp.dat.a[i][j + 1] + 1;
			else break;
		for (int j = i + 1; j <= n; j++)
			if (a[j][pos] && tmp.dat.a[i][j - 1] < inf) tmp.dat.a[i][j] = tmp.dat.a[i][j - 1] + 1;
			else break;
	}
}

void build(int p, int l, int r) {
	t[p].l = l;
	t[p].r = r;
	if (l == r) {
		init(t[p], l);
		return;
	}
	int mid = l + r >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
	t[p].dat = t[p << 1].dat * t[p << 1 | 1].dat;
}

void modify(int p, int pos) {
	if (t[p].l == t[p].r) {
		init(t[p], pos);
		return;
	}
	int mid = t[p].l + t[p].r >> 1;
	if (pos <= mid) modify(p << 1, pos);
	else modify(p << 1 | 1, pos);
	t[p].dat = t[p << 1].dat * t[p << 1 | 1].dat;	
}

matrix query(int p, int l, int r) {
	if (l <= t[p].l && t[p].r <= r)
		return t[p].dat;
	int mid = t[p].l + t[p].r >> 1;
	if (l <= mid && r > mid) return query(p << 1, l, r) * query(p << 1 | 1, l, r);
	else if (l <= mid) return query(p << 1, l, r);
	else return query(p << 1 | 1, l, r);
}

int main() {
	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%d", &a[i][j]);
	build(1, 1, m);
	for (int op, x, y, c, d; q; q--) {
		scanf("%d %d %d", &op, &x, &y);
		if (op == 1) a[x][y] ^= 1, modify(1, y);
		else {
			scanf("%d %d", &c, &d);
			matrix res = query(1, y, d);
			if (res.a[x][c] == inf) printf("-1\n");
			else printf("%d\n", res.a[x][c]);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值