题目链接

bzoj4456: [Zjoi2016]旅行者

题解

网格图,对于图分治,每次从中间切垂直于长的那一边,

对于切边上的点做最短路,合并在图两边的答案。

有点卡常

代码

 #include<queue>
#include<cctype>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')c = getchar();
while(c <= '9' && c >= '0') x = x * 10 + c - '0', c = getchar();
return x * f;
}
#define rg register
const int maxn = 100005;
int n,m,tot = 0,ans[maxn];
int X[maxn],Y[maxn]; struct node {
int v,next,w;
} edge[20005 << 2];
int head[maxn],num = 0;
inline void add_edge(int u,int v,int w) {
edge[++ num].v = v;edge[num].w = w; edge[num].next = head[u];head[u] = num;
edge[++ num].v = u;edge[num].w = w; edge[num].next = head[v];head[v] = num;
}
inline int id(rg int a,rg int b){return (a - 1) * m + b; }
struct Question {
int x,y,x1,y1,id;
} q[maxn],p[maxn]; int dis[maxn];
#define mp std::make_pair
#define pr std::pair<int,int>
bool vis[maxn];
std::priority_queue<pr> Q;
void dij(int x,int limx,int limy,int limx1,int limy1) {
for(int i = 1;i <= n;++ i) for(int j = 1;j <= m;++ j)
vis[id(i,j)] = 0,dis[id(i,j)] = 0x3f3f3f3f;
dis[x] = 0;
Q.push(mp(0,x));
while(!Q.empty()) {
int u = Q.top().second; Q.pop();
if(vis[u]) continue;
vis[u] = true;
for(int i = head[u];i;i = edge[i].next) {
int v = edge[i].v;
if(dis[v] > dis[u] + edge[i].w && X[v] >= limx && X[v] <= limx1 && Y[v] <= limy1 && Y[v] >= limy)
dis[v] = edge[i].w + dis[u],Q.push(mp(-dis[v],v));
}
}
} void solve(int x,int y,int x1,int y1,int l,int r) {
if(l > r) return ;
if(x1 - x > y1 - y) {
int mid = x + x1 >> 1;
for(int i = y;i <= y1 ;++ i) {
dij(id(mid,i),x,y,x1,y1);
for(int j = l;j <= r;++ j)
ans[q[j].id] = std::min(ans[q[j].id],dis[id(q[j].x,q[j].y)] + dis[id(q[j].x1,q[j].y1)]);
}
int L = l - 1,R = r + 1;
for(int i = l;i <= r;++ i) {
if(q[i].x < mid && q[i].x1 < mid)p[++ L] = q[i];
else if(q[i].x > mid && q[i].x1 > mid) p[-- R] = q[i];
}
for(int i = l ;i <= L;++ i) q[i] = p[i];
for(int i = R ;i <= r;++ i) q[i] = p[i];
solve(x,y,mid - 1,y1,l,L); solve(mid + 1,y,x1,y1,R,r);
} else {
int mid = y + y1 >> 1;
for(int i = x;i <= x1 ;++ i) {
dij(id(i,mid),x,y,x1,y1);
for(int j = l;j <= r;++ j)
ans[q[j].id] = std::min(ans[q[j].id],dis[id(q[j].x,q[j].y)] + dis[id(q[j].x1,q[j].y1)]);
}
int L = l - 1,R = r + 1;
for(int i = l;i <= r;++ i) {
if(q[i].y < mid && q[i].y1 < mid)p[++ L] = q[i];
else if(q[i].y > mid && q[i].y1 > mid) p[-- R] = q[i];
}
for(int i = l ;i <= L;++ i) q[i] = p[i];
for(int i = R ;i <= r;++ i) q[i] = p[i];
solve(x,y,x1,mid - 1,l,L); solve(x,mid + 1,x1,y1,R,r);
}
}
int main() {
//freopen("6.in","r",stdin);
n = read(), m = read();
for(int i = 1;i <= n;++ i) for(int j = 1;j < m;++ j)
add_edge(id(i,j),id(i,j + 1),read());
for(int i = 1;i < n;++ i) for(int j = 1;j <= m;++ j)
add_edge(id(i,j),id(i + 1,j),read());
for(int i = 1;i <= n;++ i) for(int j = 1;j <= m;++ j) X[id(i,j)] = i,Y[id(i,j)] = j;
int T = read();
while(T --) {
Question &a = q[++ tot];
a.x = read(),a.y = read(),a.x1 = read(),a.y1 = read();a.id = tot;
if(a.x == a.x1 && a.y == a.y1) ans[tot] = 0;
else ans[tot] = 0x3f3f3f3f;
}
solve(1,1,n,m,1,tot);
for(int i = 1;i <= tot;++ i) printf("%d\n",ans[i]);
return 0;
}

bzoj4456: [Zjoi2016]旅行者的更多相关文章

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

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

  2. BZOJ4456 ZJOI2016旅行者(分治+最短路)

    感觉比较套路,每次在长边中轴线处切一刀,求出切割线上的点对矩形内所有点的单源最短路径,以此更新每个询问,递归处理更小的矩形.因为若起点终点跨过中轴线是肯定要经过的,而不跨过中轴线的则可以选择是否经过中 ...

  3. [BZOJ4456][ZJOI2016]旅行者:分治+最短路

    分析 类似于点分治的思想,只统计经过分割线的最短路,然后把地图一分为二. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(regist ...

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

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

  5. 【BZOJ-4456】旅行者 分治 + 最短路

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

  6. 【BZOJ4456】旅行者(最短路,分治)

    [BZOJ4456]旅行者(最短路,分治) 题面 BZOJ Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北 的道路,这些 ...

  7. 4456: [Zjoi2016]旅行者

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

  8. P3350 [ZJOI2016]旅行者

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

  9. luogu3350 [ZJOI2016]旅行者

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

随机推荐

  1. BFC的个人理解

    BFC是Block Formatting Context (块级格式化上下文)的缩写,是一个独立的渲染区域,这个东西的存在是为了隔绝一些内部子元素对外部元素的影响. 例如: 我们用overflow:h ...

  2. 对Property进行RACObserve

    @property (assign,nonatomic) int price; @property (assign,nonatomic) int time; [RACObserve(self,pric ...

  3. Spark记录-Scala函数

    Scala函数 Scala有函数和方法. Scala方法是一个具有名称和签名的类的一部分. Scala中的函数是一个可以分配给变量的完整对象. 函数定义可以出现在源文件中的任何位置. 不带参数的函数 ...

  4. bzoj千题计划253:bzoj2154: Crash的数字表格

    http://www.lydsy.com/JudgeOnline/problem.php?id=2154 #include<cstdio> #include<algorithm> ...

  5. Javascript Jquery 中的数组定义与操作

    1.认识数组 数组就是某类数据的集合,数据类型可以是整型.字符串.甚至是对象Javascript不支持多维数组,但是因为数组里面可以包含对象(数组也是一个对象),所以数组可以通过相互嵌套实现类似多维数 ...

  6. bellman-ford算法(判断有没有负环)

    #include <iostream> #include <vector> #include<string> #include<cstring> usi ...

  7. JQuery效果隐藏/显示

    hide() 方法 语法 $(selector).hide(speed,callback) show() 方法 语法 $(selector).show(speed,callback) 参数 描述 sp ...

  8. 关于tp5 的验证码遇到的一些问题

    问题1: 网上大部分给的安装包是: composer require topthink/think-captcha 但是会提示你下载失败说要你回复*****的原始数据啥的 那可能是因为你的安装环境版本 ...

  9. 解析URL参数

    1.拿到一个完整url后,如何解析该url得到里面的参数. /** * 解析url中参数信息,返回参数数组 */ function convertUrlQuery($query) { $queryPa ...

  10. IntelliJ IDEA JRebel Maven Tomcat 实现热部署

    一,JRebel 插件 获取与安装 直接在 IDEA 中操作获取 JRebel 插件 Paste_Image.png Paste_Image.png 安装完成,记得重启 IDEA 使刚才安装的插件生效 ...