CodeForces413E Maze 2D

题意

给一个\(2*n\)的迷宫,有障碍物,\(m\)次询问,每次查询两点间最短路

题解

把上下当成一个点,每个点有上下两个接口
用线段树维护
根据地图初始化每个点信息
然后合并区间信息(类似\(floyd\))
想明白了写出来还是很简单
然后查询两点距离即可

为什么这样不会错?
画图可以知道
因为宽为\(2\)
所以最短路肯定不会先在区间外绕一圈再回来
所以查询也是直接查询两点在区间内的最小距离就是答案
如果宽更大就必须保证不能向左走才可以这么做(不然为什么还需要最短路算法,线段树还支持修改)
比如宽为\(3\)时就可能区间内不联通
但是可以绕一圈到达

#include<bits/stdc++.h>

using namespace std;

#define gc c=getchar()
#define r(x) read(x)
#define ls (rt<<1)
#define rs (rt<<1|1)

template<typename T>
inline void read(T&x){
    x=0;T k=1;char gc;
    while(!isdigit(c)){if(c=='-')k=-1;gc;}
    while(isdigit(c)){x=x*10+c-'0';gc;}x*=k;
}

const int INF=1e9;

const int N=2e5;

char s[2][N];

struct seg{
	int dist[2][2];
	
	const int* operator [](const int &x)const{
		return dist[x];
	}
	
	int* operator [](const int &x){
		return dist[x];
	}
	
}tr[N<<2];

inline seg operator +(const seg &a,const seg &b){
	seg ret;
	for(int i=0;i<2;++i){
		for(int j=0;j<2;++j){
			ret[i][j]=INF;
			for(int k=0;k<2;++k)ret[i][j]=min(ret[i][j],a[i][k]+b[k][j]+1);
		}
	}
	return ret;
}

inline void build(int rt,int l,int r){
	if(l==r){
		tr[rt][0][0]=tr[rt][0][1]=tr[rt][1][1]=tr[rt][1][0]=INF;
		if(s[0][l]=='.'){
			tr[rt][0][0]=0;
			if(s[1][l]=='.')tr[rt][0][1]=1;
		}
		if(s[1][l]=='.'){
			tr[rt][1][1]=0;
			if(s[0][l]=='.')tr[rt][1][0]=1;
		}
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	tr[rt]=tr[ls]+tr[rs];
}

inline seg query(int rt,int l,int r,int x,int y){
	if(x<=l&&r<=y)return tr[rt];
	int mid=(l+r)>>1;
	if(y<=mid)return query(ls,l,mid,x,y);
	else if(x>mid)return query(rs,mid+1,r,x,y);
	else return query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
}

int n,m;

inline int Query(int x,int y){
	int l=(x-1)%n+1;
	int r=(y-1)%n+1;
	if(l>r)swap(l,r),swap(x,y);
	return query(1,1,n,l,r)[x>n][y>n];
}

int main(){
	r(n),r(m);
	scanf("%s",s[0]+1);
	scanf("%s",s[1]+1);
	build(1,1,n);
	for(int a,b;m;--m){
		r(a),r(b);
		int ans=Query(a,b);
		if(ans==INF)ans=-1;
		printf("%d\n",ans);
	}
}

posted @ 2018-10-05 19:04  NamelessOIer  阅读(179)  评论(0编辑  收藏  举报