题面

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. java设计模式----其他模式

    1.桥接:使用桥接模式不只改变你的实现,也改变你的抽象 优点: 将实现予以解耦,让它和界面之间不再永久绑定 抽象和实现可以独立扩展,不会影响到对方 对于“具体的抽象类”所做的改变,不会影响到客户 用途 ...

  2. Python开发【2.2 异常处理】

    1.Python常见异常类型: Exception 常规错误的基类 AttributeError 对象没有这个属性 IOError 输入/输出操作失败 IndexError 序列中没有此索引(inde ...

  3. Python 005- 使用Pyecharts来绘制各种各样的图形

    本文转载自:https://blog.csdn.net/qq_39143076/article/details/79065448,如有侵权,请联系删除啊 如何做Python 的数据可视化? pyech ...

  4. python day - 17 面向对象的 类空间 和 组合

    1. 类命名空间 在类的代码中,当python 解释器在 运行的那一刻.就会在内存中开辟一个类空间,在类的空间中会加载静态变量,以及类方法的内存地址. 当类名+()(也就是实例化过程中),内存中会再次 ...

  5. Axure Base 02

    (二)Axure rp的线框图元件 l  图片 图片元件拖入编辑区后,可以通过双击选择本地磁盘中的图片,将图片载入到编辑区,axure会自动提示将大图片进行优化,以避免原型文件过大:选择图片时可以选择 ...

  6. Hibernate写hql语句与不写hql语句的区别?

    写hql语句与不写hql语句的区别? 写hql语句:书写HQL语句,所有的查询与投影的设计均使用HQL语句完成. 不写hql语句:没有任何查询语句,所有的查询与投影的设计使用面向对象格式完成. 二者选 ...

  7. BestCoder4 1002 Miaomiao's Geometry (hdu 4932) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4932 题目意思:给出 n 个点你,需要找出最长的线段来覆盖所有的点.这个最长线段需要满足两个条件:(1 ...

  8. hash与map的区别联系应用(转)

    一,hashtable原理: 哈希表又名散列表,其主要目的是用于解决数据的快速定位问题.考虑如下一个场景. 一列键值对数据,存储在一个table中,如何通过数据的关键字快速查找相应值呢?不要告诉我一个 ...

  9. C++ main函数中参数argc和argv含义及用法

    argc 是 argument count的缩写,表示传入main函数的参数个数: argv 是 argument vector的缩写,表示传入main函数的参数序列或指针,并且第一个参数argv[0 ...

  10. 【字符串】BZOJ上面几个AC自动机求最为字串出现次数的题目

    (一下只供自己复习用,目的是对比这几个题,所以写得不详细.需要细节的可以参考其他博主) [BZOJ3172:单词] 题目: 某人读论文,一篇论文是由许多(N)单词组成.但他发现一个单词会在论文中出现很 ...