题目:戳这里
题目大意:
给定一个
2∗n
的地图,某些地方是障碍,只能上下左右走,多组询问两点直接的距离。
n≤2∗105
Solution
线段树维护区间左上到右上、左下到右上、左上到右下、左下到右下的最小距离和区间两端的四个格子是否是障碍即可。合并的时候稍微有点麻烦。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
template<typename T>inline void read(T &x){
T f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
x*=f;
}
typedef long long LL;
const int maxn=200010,inf=0x7fffffff;
int n,m;
char str[2][maxn];
struct Data{
LL dis[2][2];
Data(){memset(dis,0,sizeof dis);}
};
Data operator+(Data l,Data r){
Data x;
x.dis[0][0]=min(l.dis[0][0]+r.dis[0][0],l.dis[0][1]+r.dis[1][0])+1;
x.dis[1][1]=min(l.dis[1][1]+r.dis[1][1],l.dis[1][0]+r.dis[0][1])+1;
x.dis[0][1]=min(l.dis[0][0]+r.dis[0][1],l.dis[0][1]+r.dis[1][1])+1;
x.dis[1][0]=min(l.dis[1][0]+r.dis[0][0],l.dis[1][1]+r.dis[1][0])+1;
return x;
}
struct Segment_Tree{
#define lc x<<1
#define rc x<<1|1
Data T[maxn<<2];
int L[maxn<<2],R[maxn<<2];
Segment_Tree(){
memset(L,0,sizeof L);
memset(R,0,sizeof R);
}
void Build(int x,int l,int r){
if((L[x]=l)==(R[x]=r)){
T[x].dis[0][1]=T[x].dis[1][0]=1;T[x].dis[0][0]=T[x].dis[1][1]=0;
if(str[0][l]=='X')T[x].dis[0][0]=T[x].dis[0][1]=T[x].dis[1][0]=inf;
if(str[1][l]=='X')T[x].dis[1][1]=T[x].dis[0][1]=T[x].dis[1][0]=inf;
return;
}
int mid=(l+r)>>1;
Build(lc,l,mid);Build(rc,mid+1,r);
T[x]=T[lc]+T[rc];
}
Data Query(int x,int l,int r){
if(L[x]>=l&&R[x]<=r)return T[x];
int mid=(L[x]+R[x])>>1;
Data temp;
if(l<=mid&&r>mid)temp=Query(lc,l,r)+Query(rc,l,r);
else if(l<=mid)temp=Query(lc,l,r);
else temp=Query(rc,l,r);
return temp;
}
}tree;
int main(){
read(n);read(m);
scanf("%s%s",str[0]+1,str[1]+1);
tree.Build(1,1,n);
while(m--){
int u,v;
bool f=false,g=false;
read(u);read(v);
if(u>n)u-=n,f=true;
if(v>n)v-=n,g=true;
if(u>v)swap(u,v),swap(f,g);
if(u==v)printf("%d\n",f^g);
else{
Data temp=tree.Query(1,u,v);
printf("%lld\n",temp.dis[f][g]>=inf?-1:temp.dis[f][g]);
}
}
return 0;
}