JZOJ 6293. 2019.08.12【NOIP提高组A】迷宫

D e s c r i p t i o n Description Description

给定一个 n × m n\times m n×m的矩阵,每个格子都有对应的通行情况,求单点带修最短路

数据范围: n ≤ 5 , m ≤ 2 × 1 0 5 n\leq 5,m\leq 2\times 10^5 n5,m2×105


S o l u t i o n Solution Solution

莫得修改这就是一个广义矩阵乘法加速递推

加上修改的话套一棵线段树即可,时间复杂度: O ( ( m + q l o g m ) n 3 ) O((m+qlogm)n^3) O((m+qlogm)n3)

可以用向量优化每次修改重构矩阵的时间,但由于比者太懒没打QwQ

。。。
暂时 r a n k 1 rank 1 rank1,欢迎来怼


C o d e Code Code

#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast") 
%:pragma GCC optimize("inline")
#include
#include
#include
#include
#define N 200010
#define LL long long
using namespace std;int n,m,q,opt,x,y,tx,ty,res;
bool a[5][N],up,dw;
inline LL read()
{
	char c;LL f=0,d=1;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
struct matrix
{
	int a[5][5];
	matrix(){memset(a,0x3f,sizeof(a));}
}ans;
bool flag;
matrix operator*(const matrix &a,const matrix &b)
{
	matrix c;
	for(register int i=0;i<n;i++)
	 for(register int j=0;j<n;j++)
	  for(register 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 xds
{
	#define lson k<<1
	#define rson k<<1|1
	matrix dat[N<<2];
	inline void rebuild(int k,int x)
	{
		memset(dat[k].a,0x3f,sizeof(dat[k].a));
		for(register int i=0;i<n;i++)
		{
			up=1;dw=1;
			if(a[i][x]==0) {memset(dat[k].a[i],0x3f,sizeof(dat[k].a[i]));continue;}
			for(register int j=0;j<n;j++)
			{
				if(i+j>=n||a[i+j][x]==0) up=0;
				if(i-j<0||a[i-j][x]==0) dw=0;
				if(up+dw==0) break;
				if(up) dat[k].a[i+j][i]=j+1;
				if(dw) dat[k].a[i-j][i]=j+1;
			}
		}
		return;
	}
	inline void build(int k=1,int l=1,int r=m)
	{
		if(l==r)
		{
			rebuild(k,l);
			return;
		}
		int mid=l+r>>1;
		build(lson,l,mid);build(rson,mid+1,r); 
		dat[k]=dat[lson]*dat[rson];
		return;
	}
	inline void quary(int ql,int qr,int k=1,int l=1,int r=m)
	{
		if(ql<=l&&r<=qr) {if(!flag) ans=dat[k],flag=true;else ans=ans*dat[k];return;}
		int mid=l+r>>1;
		if(ql<=mid) quary(ql,qr,lson,l,mid);
		if(qr>mid) quary(ql,qr,rson,mid+1,r);
		return;
	}
	inline void modify(int x,int k=1,int l=1,int r=m)	
	{
		if(l==r)
		{
			rebuild(k,l);
			return;
		}
		int mid=l+r>>1;
		if(x<=mid) modify(x,lson,l,mid);
		else modify(x,rson,mid+1,r);
		dat[k]=dat[lson]*dat[rson];
		return;
	}
	#undef lson
	#undef rson
}T;
signed main()
{
	freopen("maze.in","r",stdin);
	freopen("maze.out","w",stdout);
	n=read();m=read();q=read();
	for(register int i=0;i<n;i++) for(register int j=1;j<=m;j++) a[i][j]=read();
	T.build();
	while(q--)
	{
		opt=read();
		if(opt==1) x=read()-1,y=read(),a[x][y]^=1,T.modify(y);
		else
		{
			x=read()-1;y=read();tx=read()-1;ty=read();
			if(y>ty) {puts("-1");continue;}
			if(y==ty)
			{
				if(x>tx) swap(x,tx);flag=1;
				for(register int i=x;i<=tx;i++) if(a[i][y]==0) {flag=false;break;}
				if(!flag) puts("-1");else printf("%d\n",tx-x);
				continue;
			}
			flag=0;T.quary(y,ty-1);
			up=dw=1;
			res=0x3f3f3f3f;
			for(register int i=0;i<n;i++)
			{
				if(tx+i>=n||a[tx+i][ty]==0) up=0;
				if(tx-i<0||a[tx-i][ty]==0) dw=0;
				if(up+dw==0) break;
				if(up) 
				res=min(res,ans.a[x][tx+i]+i);
				if(dw) 
				res=min(res,ans.a[x][tx-i]+i);
			}
			if(res>n*m) puts("-1");else printf("%d\n",res);
		}
	}
}

你可能感兴趣的:(ddp,dp,矩阵乘法,线段树)