正题
题目大意
一个n∗mn*mn∗m的迷宫,不能往左走,有墙,每次修改一个点或询问两个点之间的最短距离。
解题思路
考虑到nnn的值很小,所以我们可以用矩阵转移,然后要求支持修改和查询所以我们考虑ddpddpddp。
我们可以用矩阵代替线段树的权值,然后区间查询即可。
时间复杂度O((m+qlogm)n3)O((m+q\log m)n^3)O((m+qlogm)n3)
codecodecode
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Size=5,N=201000;
struct Matrix{int a[Size][Size];
}c,ans;
struct Tree_node{int l,r;Matrix w;
}t[N*4];
int n,m,q,v[Size][N],flag;
Matrix operator*(const Matrix &a,const Matrix &b)
{memset(c.a,0x3f,sizeof(c.a));for(int i=0;i<n;i++)for(int j=0;j<n;j++)for(int k=0;k<n;k++)c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]);return c;
}
struct Seq_Tree{void Build(int x,int l,int r){memset(t[x].w.a,0x3f,sizeof(t[x].w.a));t[x].l=l;t[x].r=r;if(l==r){for(int i=0;i<n;i++){bool up=1,down=1;if(!v[i][l]){continue;}for(int j=0;j<n;j++){if(i+j>=n||!v[i+j][l]) up=0;if(i-j<0||!v[i-j][l]) down=0;if(!up&&!down) break;if(up) t[x].w.a[i+j][i]=j+1;if(down) t[x].w.a[i-j][i]=j+1; }}return;}int mid=(l+r)/2;Build(x*2,l,mid);Build(x*2+1,mid+1,r);t[x].w=t[x*2].w*t[x*2+1].w;}void Ask(int x,int l,int r){if(t[x].l==l&&t[x].r==r){if(!flag) ans=t[x].w,flag=1;else ans=ans*t[x].w;return;}int mid=(t[x].l+t[x].r)/2;if(r<=mid) Ask(x*2,l,r);else if (l>mid) Ask(x*2+1,l,r);else Ask(x*2,l,mid),Ask(x*2+1,mid+1,r);}void Change(int x,int z){if(t[x].l==t[x].r){memset(t[x].w.a,0x3f,sizeof(t[x].w.a));int l=t[x].l;for(int i=0;i<n;i++){bool up=1,down=1;if(!v[i][l]){memset(t[x].w.a[i],0x3f,sizeof(t[x].w.a[i]));continue;}for(int j=0;j<n;j++){if(i+j>=n||!v[i+j][l]) up=0;if(i-j<0||!v[i-j][l]) down=0;if(!up&&!down) break;if(up) t[x].w.a[i+j][i]=j+1;if(down) t[x].w.a[i-j][i]=j+1; }}return;}int mid=(t[x].l+t[x].r)/2;if(z<=mid) Change(x*2,z);else Change(x*2+1,z);t[x].w=t[x*2].w*t[x*2+1].w; }
}T;
int main()
{freopen("maze.in","r",stdin);freopen("maze.out","w",stdout);scanf("%d%d%d",&n,&m,&q);for(int i=0;i<n;i++)for(int j=1;j<=m;j++)scanf("%d",&v[i][j]);T.Build(1,1,m);while(q--){int op,a,b,x,y;scanf("%d%d%d",&op,&a,&b);if(op==1){a--;v[a][b]=!v[a][b];T.Change(1,b);}if(op==2){scanf("%d%d",&x,&y);if(y<b){printf("-1\n");continue;}if(b==y){if(x>a) swap(x,a);x--;a--;flag=0;for(int i=x;i<=a;i++)if(!v[i][b]){flag=1;break;}if(flag) printf("-1\n");else printf("%d\n",a-x);continue;}flag=0;T.Ask(1,b,y-1);x--;a--;bool up=1,down=1;int mins=2147483647;for(int i=0;i<n;i++){if(x+i>=n||!v[x+i][y]) up=0;if(x-i<0||!v[x-i][y]) down=0;if(!up&&!down) break;if(up) mins=min(mins,ans.a[a][x+i]+i);if(down) mins=min(mins,ans.a[a][x-i]+i); } if(mins>n*m){printf("-1\n");continue;}printf("%d\n",mins);}}
}