【维护】【线段树】CF413E Maze 2D
题目大意
给定一个\(2\times n\) 的矩阵,黄色方格代表不能通行,蓝色格子代表畅通无阻,同时对每一个方格进行编号,求编号为x到编号为y的最短路。
思路
先不考虑是具体地从哪里到哪里,而是先进行一个笼统地分析。
单单去考虑从第i行到第j行的最短路。
一共有四种方案:
- 左上角到右上角uu
- 左上角到右下角ud
- 左下角到右上角du
- 左下角到右下角dd
而这就是我们需要进行维护的数据
struct data{
int d1,d2,d3,d4;
}
初始化和合并
当考虑长度为1的区间的时候,左上角和右上角是重叠的,左下角和右下角是重叠的。
要得到区间为1到9的数据我们只需知道区间1到5的信息和区间6到9的信息。
比如要求得区间1到9从左上角到右上角的最短路。
我们有两种走法
一种是从区间1到5的左上角走到其右上角,再接着从区间6到9的左上角走到区间6到9的右上角。
另外一种是从区间1到5的左上角走到其右下角,再接着从区间6到9的左下角走到区间6到9的右上角。
Code
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
using namespace std;
const int N = 2E5+500,inf = 8e5+500;
int n,m;
struct Data{
int uu,ud,du,dd;
};
struct Seg_Tree{
int l,r;
Data data;
}tr[N<<2];
bool maze[2][N];
Data merge(Data x,Data y)
{
Data temp = {inf,inf,inf,inf};
temp.uu = min(inf, min( x.ud+y.du+1 , x.uu+y.uu+1 ) );
temp.ud = min(inf, min( x.ud+y.dd+1 , x.uu+y.ud+1 ) );
temp.du = min(inf, min( x.dd+y.du+1 , x.du+y.uu+1 ) );
temp.dd = min(inf, min( x.dd+y.dd+1 , x.du+y.ud+1 ) );
return temp;
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u].data = {inf,inf,inf,inf};
if(maze[0][l]) tr[u].data.uu = 0;
if(maze[1][l]) tr[u].data.dd = 0;
if(maze[0][l]&&maze[1][l]) tr[u].data.du = tr[u].data.ud = 1;
return ;
}
int mid = l + r >> 1 ;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
tr[u].data = merge(tr[u<<1].data,tr[u<<1|1].data);
}
Data query(int u,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
return tr[u].data;
int mid = l + r >> 1;
if(mid>=y) return query(u<<1,l,mid,x,y);
if(mid+1<=x) return query(u<<1|1,mid+1,r,x,y);
return merge( query(u<<1,l,mid,x,y) , query(u<<1|1,mid+1,r,x,y) );
}
int ask(int x,int y)
{
int rowx = (x>=n+1) + 1 , rowy = (y>=n+1) + 1;
int colx = x-(rowx==2?n:0) , coly = y-(rowy==2?n:0);
if(colx>coly) swap(colx,coly),swap(rowx,rowy);
Data ans = query(1,1,n,colx,coly);
int res;
if(rowx==1&&rowy==1) res = ans.uu;
else if(rowx==1&&rowy==2) res = ans.ud;
else if(rowx==2&&rowy==1) res = ans.du;
else if(rowx==2&&rowy==2) res = ans.dd;
if(res==inf) return -1;
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=0;i<=1;i++)
{
string s;
cin>>s;
for(int j=0;j<s.length();j++)
if(s[j]=='.') maze[i][j+1] = 1;
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
cout<<ask(x,y)<<endl;
}
return 0;
}