题面

https://www.lydsy.com/JudgeOnline/problem.php?id=4456

题解

分治

设当前work的区间为(x1,y1,x2,y2)

我们将长边分成两半

不妨设长边是(x1,x2)

那么令mid=(x1+x2)/2

对于分界线(mid,y1)~(mid,y2)的所有点 我们做最短路

得到分界线上所有点到区间里任意点的最短路

那么对于询问(sx,sy,tx,ty) 我们可以枚举分界线上某一点(mid,y) 并且用dist((mid,y),(sx,sy))+dist((mid,y),(tx,ty))更新答案

然后对于(sx,sy)和(tx,ty)都落在分界线同一侧的询问我们递归求解

这样做的正确性:每一组询问,一定会经过某次的分界线,在计算到这条分界线的时候就可以算到答案

复杂度:T(n)=4T(n/2)+O(n*(m+nlogm))  m为边数也就是n^2

那么T(n)=n^3(这是n约等于m的情况) 可以通过这道题

n和m差距大的时候更快

Code

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll; ll read(){
ll x=,f=;char c=getchar();
while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
while(c>='' && c<=''){x=x*+c-'';c=getchar();}
return x*f;
} const int maxn=;
int n,m,q;
int a[][maxn],b[][maxn];
bool vis[][maxn];
bool flag;
int res[]; struct P{
int x;
pair<int,int> y;
bool operator <(const P &a) const{
return x>a.x;
}
}; priority_queue<P> pq; struct query{
int a,b,c,d;
int p,ans;
void input(){
a=read(),b=read(),c=read(),d=read();
}
} que[]; int dis[][maxn];
int num[][maxn]; void update(int nwx,int nwy,int nwdis){
//cout<<nwx<<' '<<nwy<<' '<<nwdis<<endl;
if(dis[nwx][nwy]>nwdis){
dis[nwx][nwy]=nwdis;
pq.push(P{nwdis,make_pair(nwx,nwy)});
}
}
void doit(int x,int y,int X1,int Y1,int X2,int Y2){
//cout<<X1<<' '<<Y1<<' '<<X2<<' '<<Y2<<' '<<x<<' '<<y<<endl;
for(int i=X1;i<=X2;i++)
for(int j=Y1;j<=Y2;j++)
dis[i][j]=1e9,vis[i][j]=;
dis[x][y]=;
pq.push(P{,make_pair(x,y)});
while(!pq.empty()){
P nw=pq.top();
pq.pop();
int X=nw.y.first,Y=nw.y.second;
//cout<<X<<' '<<Y<<' '<<dis[X][Y]<<endl;
if(vis[X][Y]) continue;
vis[X][Y]=;int dist=dis[X][Y];
if(X>X1) update(X-,Y,dist+b[X-][Y]);
if(X<X2) update(X+,Y,dist+b[X][Y]);
if(Y>Y1) update(X,Y-,dist+a[X][Y-]);
if(Y<Y2) update(X,Y+,dist+a[X][Y]);
}
} void solve(int nwa,int nwb,int nwc,int nwd,int l,int r){
//cout<<nwa<<' '<<nwb<<' '<<nwc<<' '<<nwd<<endl;
if(l>r) return;
int len1=nwc-nwa+,len2=nwd-nwb+;
if(len1>=len2){
int md=(nwa+nwc)>>;
for(int j=nwb;j<=nwd;j++){
doit(md,j,nwa,nwb,nwc,nwd);
for(int k=l;k<=r;k++){
//cout<<que[k].p<<' '<<dis[que[k].a][que[k].b]<<' '<<dis[que[k].c][que[k].d]<<endl;
que[k].ans=min(que[k].ans,dis[que[k].a][que[k].b]+dis[que[k].c][que[k].d]);
}
}
if(nwa<md){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].a<md && que[i].c<md) pos++,swap(que[i],que[pos]);
}
solve(nwa,nwb,md-,nwd,l,pos);
}
if(md<nwc){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].a>md && que[i].c>md) pos++,swap(que[i],que[pos]);
}
solve(md+,nwb,nwc,nwd,l,pos);
}
}
else{
int md=(nwb+nwd)>>;
for(int i=nwa;i<=nwc;i++){
doit(i,md,nwa,nwb,nwc,nwd);
for(int k=l;k<=r;k++){
//cout<<que[k].p<<' '<<dis[que[k].a][que[k].b]<<' '<<dis[que[k].c][que[k].d]<<endl;
que[k].ans=min(que[k].ans,dis[que[k].a][que[k].b]+dis[que[k].c][que[k].d]);
}
}
if(nwb<md){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].b<md && que[i].d<md) pos++,swap(que[i],que[pos]);
}
solve(nwa,nwb,nwc,md-,l,pos);
}
if(md<nwd){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].b>md && que[i].d>md) pos++,swap(que[i],que[pos]);
}
solve(nwa,md+,nwc,nwd,l,pos);
}
}
} int main(){
#ifdef LZT
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
n=read();m=read();
if(n>m) flag=;
for(int i=;i<=n;i++){
for(int j=;j<m;j++){
if(!flag) a[i][j]=read();
else b[j][i]=read();
}
}
for(int i=;i<n;i++){
for(int j=;j<=m;j++){
if(!flag) b[i][j]=read();
else a[j][i]=read();
}
}
q=read();
for(int i=;i<=q;i++){
que[i].input();
if(flag) swap(que[i].a,que[i].b),swap(que[i].c,que[i].d);
que[i].p=i;que[i].ans=2e9;
}
if(flag) swap(n,m); solve(,,n,m,,q); for(int i=;i<=q;i++)
res[que[i].p]=que[i].ans;
for(int i=;i<=q;i++)
printf("%d\n",res[i]);
return ;
} /*
2 2
2
3
6 4
2
1 1 2 2
1 2 2 1
*/

Review

分治还是比较明显的

然而数据的处理十分麻烦

因为条件是n×m的范围

所以我们得同时考虑n=m和n>>m的情况

代码中的处理方法是跟别人学的 很棒棒 要多写几遍

bzoj 4456 [Zjoi2016]旅行者的更多相关文章

  1. BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)

    题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...

  2. 4456: [Zjoi2016]旅行者

    4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...

  3. ●BOZJ 4456 [Zjoi2016]旅行者

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解: 分治好题.大致做法如下:对于一开始的矩形区域,过较长边的中点把矩形区域分为两个 ...

  4. [BZOJ4456] [Zjoi2016]旅行者 分治+最短路

    4456: [Zjoi2016]旅行者 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 777  Solved: 439[Submit][Status] ...

  5. P3350 [ZJOI2016]旅行者

    题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...

  6. bzoj4456: [Zjoi2016]旅行者

    题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...

  7. 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路

    [BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...

  8. Luogu 3350 [ZJOI2016]旅行者

    BZOJ 4456 听若干个大佬讲过$n$遍终于写掉了. 我把时限基本上跑满了2333…… 分治 + 最短路. 首先我们去分治这个矩形格子,找到一条长边把它对半切,对切开的边上的每一个点跑一遍最短路然 ...

  9. luogu3350 [ZJOI2016]旅行者

    链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...

随机推荐

  1. 关于UDID和UUID的区别

    关于UDID和UUID的区别   一.UDID(Unique Device Identifier) UDID是Unique Device Identifier的缩写,中文意思是设备唯一标识. 在很多需 ...

  2. Service Mesh vs SideCar

    Istio = 微服务框架 + 服务治理 Istio 大幅降低微服务架构下应用程序的开发难度,势必极大的推动微服务的普及.个人乐观估计,随着isito的成熟,微服务开发领域将迎来一次颠覆性的变革.后面 ...

  3. 安卓动态逆向分析工具--Andbug&Androguard

    工具使用方法: 转自: http://bbs.pediy.com/showthread.php?t=183412 https://testerhome.com/topics/3542 安装andbug ...

  4. 最长公共字序列.cpp

    <span style="color:#993399;">/* By yuan 2014/6/21 At nwpu.xf 1041.最长公共子序列 时限:1000ms ...

  5. Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo DP+矩阵快速幂加速

    E. Okabe and El Psy Kongroo     Okabe likes to take walks but knows that spies from the Organization ...

  6. A Practical Introduction to Blockchain with Python

    A Practical Introduction to Blockchain with Python // Adil Moujahid // Data Analytics and more http: ...

  7. C++虚复制构造函数,设置Clone()方法返回基类指针,并设置为虚函数

    构造函数不能是虚函数.但有时候确实需要能传递一个指向基类对象的指针,并且有已创建的派生类对象的拷贝.通常在类内部创建一个Clone()方法,并设置为虚函数. //Listing 12.11 Virtu ...

  8. Linux Linker

    文章原文:http://zhidao.baidu.com/link?url=U2Mtcc6BKi4vuQ1MO8U6s9gNm4y9Epphz03veA2lVpRWMozyVdj0PYvw1ZU9qj ...

  9. Http常用状态码及含义

    HTTP 400 – 请求无效 HTTP 404- 无法找到文件或目录 HTTP 500 – 内部服务器错误 HTTP 502 – 网关错误 HTTP 400 – 请求无效 HTTP 401.1 – ...

  10. 微信的API都是通过https调用实现的,分为post方法调用和get方法调用。不需要上传数据的采用get方法(使用IntraWeb开发)

    首先需要明确的是,微信的API都是通过https调用实现的,分为post方法调用和get方法调用.不需要上传数据的采用get方法(例如获取AccessToken),而需要向微信服务器提交数据的采用po ...