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);
}
}