题意
给出一个矩阵,里面有些墙,有两种操作:
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]);
}
}
}