题目:
题意:
有两种操作,一个是将某个位置的格子的状态取反,另一个是对于指定的起点和终点求出它们之间的距离
我们只能向上、下、右三个方向移动
分析:
因为不能想左移动,所以不会存在后效性
这样也就说明
d
d
p
ddp
ddp是可行的
不同于普通的
d
p
dp
dp,我们用矩阵来转移状态,同时用线段树来维护
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define LZX Mu
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int qwq[6][200005],n,m,q,tf;
struct ddp{
int a[6][6];
}ans;
ddp operator *(const ddp &a,const ddp &b)
{
ddp c;
memset(c.a,0x3f,sizeof(c.a));
for(register int i=1;i<=n;i++)
for(register int j=1;j<=n;j++)
for(register int k=1;k<=n;k++)
c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
struct tree{
int l,r;ddp w;
}t[800005];
void build(int k,int l,int r)
{
memset(t[k].w.a,0x3f,sizeof(t[k].w.a));
t[k].l=l;t[k].r=r;
if(l==r)
{
for(register int i=1;i<=n;i++)
{
int up=1,down=1;
if(!qwq[i][l]) continue;
t[k].w.a[i][i]=1;
for(register int j=1;j<=n;j++)
{
if(i+j>n||!qwq[i+j][l]) up=0;
if(i-j<1||!qwq[i-j][l]) down=0;
if(!up&&!down) break;
if(up) t[k].w.a[i+j][i]=j+1;
if(down) t[k].w.a[i-j][i]=j+1;
}
}
return;
}
int mid=(l+r)>>1;
build(k*2,l,mid);build(k*2+1,mid+1,r);
t[k].w=t[k*2].w*t[k*2+1].w;
return;
}
void change(int k,int z)
{
if(t[k].l==t[k].r)
{
memset(t[k].w.a,0x3f,sizeof(t[k].w.a));
int l=t[k].l;
for(register int i=1;i<=n;i++)
{
int up=1,down=1;
if(!qwq[i][l]) continue;
t[k].w.a[i][i]=1;
for(register int j=1;j<=n;j++)
{
if(i+j>n||!qwq[i+j][l]) up=0;
if(i-j<1||!qwq[i-j][l]) down=0;
if(!up&&!down) break;
if(up) t[k].w.a[i+j][i]=j+1;
if(down) t[k].w.a[i-j][i]=j+1;
}
}
return;
}
int mid=(t[k].l+t[k].r)>>1;
if(z<=mid) change(k*2,z);
else change(k*2+1,z);
t[k].w=t[k*2].w*t[k*2+1].w;
return;
}
void ask(int k,int l,int r)
{
if(t[k].l==l&&t[k].r==r)
{
if(!tf) ans=t[k].w,tf=1;
else ans=ans*t[k].w;
return;
}
int mid=(t[k].l+t[k].r)>>1;
if(r<=mid) ask(k*2,l,r);
else if(l>mid) ask(k*2+1,l,r);
else ask(k*2,l,mid),ask(k*2+1,mid+1,r);
return;
}
int main()
{
freopen("maze.in","r",stdin);
freopen("maze.out","w",stdout);
n=read(),m=read(),q=read();
for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) qwq[i][j]=read();
build(1,1,m);
while(q--)
{
int o=read();
if(o==1)
{
int a=read(),b=read();
qwq[a][b]=!qwq[a][b];
change(1,b);
}
else
{
int a=read(),b=read(),x=read(),y=read();
if(b==y)
{
if(a>x) swap(x,a);
if(y<b) {printf("-1\n");continue;}
tf=0;
for(int i=a;i<=x;i++) if(!qwq[i][y]) {tf=1;break;}
if(tf) printf("-1\n"); else printf("%d\n",x-a);
continue;
}
tf=0;ask(1,b,y-1);
int up=1,down=1;
int minn=2147483647;
for(register int i=0;i<=n;i++)
{
if(x+i>n||!qwq[x+i][y]) up=0;
if(x-i<1||!qwq[x-i][y]) down=0;
if(!up&&!down) break;
if(up) minn=min(minn,ans.a[a][x+i]+i);
if(down) minn=min(minn,ans.a[a][x-i]+i);
}
if(minn>n*m) {printf("-1\n");continue;}
printf("%d\n",minn);
}
}
return 0;
}