题目链接:Codeforces - Maze 2D
这种特殊数据,我们可以想到线段树。
线段树处理这种问题需要考虑的就是区间合并。怎么合并呢?
我们令:
d1为左上角到右上角的最短路。
d2为左下角到右下角的最短路。
d3为左上角到右下角的最短路。
d4为左下角到右上角的最短路。
那么两端区间是很好合并的。
t[p].d1=min(inf,min(ls.d1+rs.d1,ls.d3+rs.d4)+1);
t[p].d2=min(inf,min(ls.d2+rs.d2,ls.d4+rs.d3)+1);
t[p].d3=min(inf,min(ls.d1+rs.d3,ls.d3+rs.d2)+1);
t[p].d4=min(inf,min(ls.d2+rs.d4,ls.d4+rs.d1)+1);
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
int n,m,g[3][N]; char str[N];
struct node{int d1,d2,d3,d4;}t[N<<2];
inline void push_up(int p){
node ls=t[p<<1],rs=t[p<<1|1];
t[p].d1=min(inf,min(ls.d1+rs.d1,ls.d3+rs.d4)+1);
t[p].d2=min(inf,min(ls.d2+rs.d2,ls.d4+rs.d3)+1);
t[p].d3=min(inf,min(ls.d1+rs.d3,ls.d3+rs.d2)+1);
t[p].d4=min(inf,min(ls.d2+rs.d4,ls.d4+rs.d1)+1);
}
void build(int p,int l,int r){
if(l==r){
t[p].d1=t[p].d2=t[p].d3=t[p].d4=inf;
if(g[1][l]) t[p].d1=0;
if(g[2][l]) t[p].d2=0;
if(g[1][l]&&g[2][l]) t[p].d3=t[p].d4=1; return ;
}
int mid=l+r>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
push_up(p);
}
node ask(int p,int l,int r,int ql,int qr){
if(l==ql&&r==qr) return t[p];
int mid=l+r>>1;
if(qr<=mid) return ask(p<<1,l,mid,ql,qr);
else if(ql>mid) return ask(p<<1|1,mid+1,r,ql,qr);
else{
node ls=ask(p<<1,l,mid,ql,mid),rs=ask(p<<1|1,mid+1,r,mid+1,qr),res;
res.d1=min(inf,min(ls.d1+rs.d1,ls.d3+rs.d4)+1);
res.d2=min(inf,min(ls.d2+rs.d2,ls.d4+rs.d3)+1);
res.d3=min(inf,min(ls.d1+rs.d3,ls.d3+rs.d2)+1);
res.d4=min(inf,min(ls.d2+rs.d4,ls.d4+rs.d1)+1);
return res;
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=2;i++){
scanf("%s",str+1);
for(int j=1;j<=n;j++) g[i][j]=(str[j]=='.');
}
build(1,1,n);
while(m--){
int x1=1,x2=1,y1,y2,ans=inf; scanf("%d %d",&y1,&y2);
if(y1>n) y1-=n,x1++;
if(y2>n) y2-=n,x2++;
if(y1>y2) swap(x1,x2),swap(y1,y2);
node res=ask(1,1,n,y1,y2);
if(x1==x2){
if(x1==1) ans=res.d1;
else ans=res.d2;
}else{
if(x1==1) ans=res.d3;
else ans=res.d4;
}
if(ans==inf) ans=-1;
printf("%d\n",ans);
}
return 0;
}