Codeforces413E Maze 2D加强版

Problem

Codeforces

n ≤ 5 , m ≤ 2 × 1 0 5 , q ≤ 5 × 1 0 4 n\leq 5,m\leq 2\times10^5,q\leq 5\times 10^4 n5,m2×105,q5×104
要求支持修改某个格子的可走状态。

Solution

感觉想法很新奇的一道题,但是后来boshi告诉我这是动态dp的套路题……所以就当是动态dp入门题了吧

我们用一个 n 2 n^2 n2的矩阵来代表一个区间的最左端到最右段的各个点间的最短距离,那么合并两个区间就可以枚举中间点, O ( n 3 ) O(n^3) O(n3)。为了方便写代码,可以把这个操作用重载运算符实现。

想到了这一点,一个自然的想法就是用线段树来搞。时间复杂度 O ( n 3 ( m + q ) log ⁡ m ) O(n^3(m+q)\log m) O(n3(m+q)logm),数据随机所以期望可过。。

Code

#include <cstring>
#include <cstdio>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=200010,INF=0x3f3f3f3f;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int n,m,q,a[6][maxn];
struct data{
	int f[6][6];
	data(){memset(f,0x3f,sizeof(f));}
	void clear(){memset(f,0x3f,sizeof(f));}
	data operator + (const data &b)const
	{
		data res;
		for(int i=1;i<=5;i++)
		  for(rg int j=1;j<=5;j++)
		    for(rg int k=1;k<=5;k++)
		      getmin(res.f[i][j],f[i][k]+b.f[k][j]+1);
		return res;
	}
}t[maxn<<2];
void build(int l,int r,int rt)
{
	if(l==r)
	{
		for(rg int i=1;i<=n;i++)
		  if(a[i][l])
		  {
			t[rt].f[i][i]=0;
			for(rg int j=i+1;j<=n;j++)
			  if(a[j][l])
			  {getmin(t[rt].f[i][j],t[rt].f[i][j-1]+1);t[rt].f[j][i]=t[rt].f[i][j];}
		  }
		return ;
	}
	int m=(l+r)>>1;
	build(l,m,rt<<1);build(m+1,r,rt<<1|1);
	t[rt]=t[rt<<1]+t[rt<<1|1];
}
void update(int l,int r,int pos,int rt)
{
	if(l==r)
	{
		t[rt].clear();
		for(rg int i=1;i<=n;i++)
		  if(a[i][l])
		  {
			t[rt].f[i][i]=0;
			for(rg int j=i+1;j<=n;j++)
			  if(a[j][l])
			  {getmin(t[rt].f[i][j],t[rt].f[i][j-1]+1);t[rt].f[j][i]=t[rt].f[i][j];}
		  }
		return ;
	}
	int m=(l+r)>>1;
	if(pos<=m) update(l,m,pos,rt<<1);
	else update(m+1,r,pos,rt<<1|1);
	t[rt]=t[rt<<1]+t[rt<<1|1];
}
data query(int l,int r,int L,int R,int rt)
{
	if(L<=l&&r<=R) return t[rt];
	int m=(l+r)>>1;
	if(R<=m) return query(l,m,L,R,rt<<1);
	if(m<L) return query(m+1,r,L,R,rt<<1|1);
	return query(l,m,L,R,rt<<1)+query(m+1,r,L,R,rt<<1|1);
}
int main()
{
	int op,x,y,c,d;data tmp;
	read(n);read(m);read(q);
	for(rg int i=1;i<=n;i++)
	  for(rg int j=1;j<=m;j++)
	    read(a[i][j]);
	build(1,m,1);
	while(q--)
	{
		read(op);read(x);read(y);
		if(op==1)
		{
			a[x][y]^=1;
			update(1,m,y,1);
		}
		else
		{
			read(c);read(d);
			if(!a[x][y]||!a[c][d]){puts("-1");continue;}
			tmp=query(1,m,y,d,1);
			printf("%d\n",(tmp.f[x][c]>=INF?-1:tmp.f[x][c]));
		}
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值