zoukankan      html  css  js  c++  java
  • 【模拟赛】纪中提高A组 19.8.12 测试 迷宫

    # Task.1 迷宫
    本来是整场比赛的题解的,但是另外两道题到现在都没搞完...

    题目大意:给出一个 \(N\times M\) 的网格状的迷宫,每个格子可能存在障碍无法通行或者可以通行,小奇被困在迷宫的某个格子中,迷宫的出口在小奇的右边,小奇只能往上、右、下方向移动。小奇的位置和迷宫的出口以及迷宫的构造会发生改变。现在给出 \(Q\) 次操作,\(opt=1\) 改变迷宫坐标为 \((a,b)\) 的格子的状态(可通行->不可通行,不可通行->可通行),\(opt=2\) 给出小奇的位置 \((a,b)\) 和迷宫的出口 \((c,d)\),询问小奇能否到达出口,若能输出最短距离,否则输出 "\(-1\)"。

    数据范围:\(1\leq N\leq 5,1\leq M\leq 2\cdot 10^5,1\leq Q\leq 5\cdot 10^4\)

    考场上没莽出来,想到了一维的情况可以线段树瞎搞。

    实际上解法确实是线段树。看到这么小的 \(N\),估摸着是状压之类的东西,但是不行。

    \(N=1\) 的情况,我们只要维护一棵线段树,节点 \([l,r]\) 存一个值 \(dis\),表示两个端点间的距离,合并时直接把 \([l,mid]\)\([mid+1,r]\)\(dis\) 加起来就得到了 \([l,r]\) 端点的距离。查询操作直接查询区间 \([l,r]\) 即可,修改时把所有包含被修改的点的区间都进行修改。

    现在看 \(N=2\) 的情况,线段树的节点需要发生些小变化,区间 \([l,r]\) 每个位置有两个格子,左右端点的位置可以两两走到或者走不到,所以节点存四个值,分别表示左上到右下,左下到右下,左上到右上,左下到右上的最短路径。合并时枚举跨过区间中点的那一步怎么走即可。查询修改和一维的一样。

    考虑 \(N\) 更大的情况,对于区间 \([l,r]\),我们的走法更多了,\(l\) 处有位置 \((i,l)\)\(r\) 处有位置 \((j,r)\),可能存在 \((i,l)\) 走到 \((j,r)\) 的最短距离 \(f_{i,j}\),有 \(N\times N\) 种情况,存储在一个矩阵中。合并时类似 \(Floyd\),依然枚举跨过中点的那一步\((k)\)怎么走、经过了哪个点,如下图:

    在查询时,查询区间 \([b,d]\) 所对应的矩阵中 \(f_{a,c}\) 的值。修改时重构节点 \([b,b]\),再更新所有包含它的节点。

    综上所述,我们维护一棵树上节点是一个类似 \(Floyd\) 的最短路的矩阵,矩阵合并 \(O(N^3)\),总复杂度 \(O(\ (M+Q) log M N^3\ )\)

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    template<class T>void read(T &x){
    	x=0; char c=getchar();
    	while(c<'0'||'9'<c)c=getchar();
    	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
    }
    typedef pair<int,int> pr;
    const int N=200050,Q=50050;
    
    int n,m,q;
    int e[7][N];
    
    void cmin(int &x,int y){if(x>y)x=y;}
    struct node{
    	int f[6][6];
    	void init(int x){
    		memset(f,0x3f,sizeof(f));
    		for(int i=1;i<=n;i++)if(e[i][x]==1)f[i][i]=0;
    		for(int len=2;len<=n;len++)
    			for(int i=1,j=i+len-1;j<=n;i++,j++)
    				cmin(f[i][j],f[i][j-1]+f[j][j]+1);
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<i;j++)
    				f[i][j]=f[j][i];
    	}
    	void merge(node u,node v){
    		node res;
    		memset(res.f,0x3f,sizeof(res.f));
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++){
    				for(int k=1;k<=n;k++)
    					cmin(res.f[i][j],u.f[i][k]+v.f[k][j]+1);
    				f[i][j]=res.f[i][j];
    			}
    	}
    	void out(){
    		for(int i=1;i<=n;i++,puts(""))
    			for(int j=1;j<=n;j++)printf("%d ",f[i][j]);
    	}
    };
    struct segt{
    #define lson l,mid,p<<1
    #define rson mid+1,r,p<<1|1
    	node s[N<<2];
    	void pushup(int p){
    		s[p].merge(s[p<<1],s[p<<1|1]);
    	}
    	void build(int l,int r,int p){
    		if(l==r){s[p].init(l); return ;}
    		int mid=(l+r)>>1;
    		build(lson); build(rson); pushup(p);
    	}
    	void upd(int x,int l,int r,int p){
    		if(l==r){s[p].init(l); return ;}
    		int mid=(l+r)>>1;
    		if(x<=mid) upd(x,lson); else upd(x,rson); pushup(p);
    	}
    	node query(int L,int R,int l,int r,int p){
    		if(L<=l&&r<=R) return s[p];
    		int mid=(l+r)>>1; node res;
    		if(L<=mid&&R<=mid) res=query(L,R,lson);
    		else if(mid<L) res=query(L,R,rson);
    		else res.merge(query(L,R,lson),query(L,R,rson));
    		return res;
    	}
    }t;
    int main(){
    //	freopen("maze.in","r",stdin);
    //	freopen("maze.out","w",stdout);
    	read(n); read(m); read(q);
    	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(e[i][j]);
    	t.build(1,m,1);
    	node res;
    	int op,a,b,c,d;
    	for(int i=1;i<=q;i++){
    		read(op); read(a); read(b);
    		if(op==1){e[a][b]^=1; t.upd(b,1,m,1);}
    		else {
    			read(c); read(d);
    			if(b>d){puts("-1"); continue;}
    			res=t.query(b,d,1,m,1);
    			if(res.f[a][c]!=0x3f3f3f3f) printf("%d\n",res.f[a][c]);
    			else puts("-1");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何:将控件锁定到 Windows 窗体
    Linux 设置字符集
    sql 批量处理
    解决表被锁了
    oracle 分页模板
    创建用户及表空间
    恢复数据库数据
    instr vs like 效率
    自定义参数转换器
    spring boot 整合MyBatis
  • 原文地址:https://www.cnblogs.com/opethrax/p/11339848.html
Copyright © 2011-2022 走看看