题目链接

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. Hadoop源码阅读-HDFS-day1

    HDFS声明及构造函数 @InterfaceAudience.Private @InterfaceStability.Evolving public class Hdfs extends Abstra ...

  2. c#:无法将 NULL 转换成“System.DateTime”,因为它是一种值类型

    摘自:http://www.blogjava.net/parable-myth/archive/2010/09/30/333454.html 在C# 2.0里面的数据类型中,分为值类型和引用类型,引用 ...

  3. bzoj千题计划285:bzoj2555: SubString

    http://www.lydsy.com/JudgeOnline/problem.php?id=2555 后缀自动机,用LCT维护parent树 一个串的出现次数 = parent 树 上 其所在状态 ...

  4. meeting,symposium,seminar 等区别

    meeting,symposium,seminar 等区别 会议分类的方式可说是不胜枚举,这点初步由英文对会议名称的写法,就可看出端倪,像是Assembly,Caucus,Colloquium, Co ...

  5. Flex 界面初始化 自定义 预加载 类!

    说明: 自定义界面初始化过程提示:初始化...,初始化完毕,加载完毕! ZPreloader.as package com.command { import flash.display.Graphic ...

  6. (叉积)B - Toy Storage POJ - 2398

    题目链接:https://cn.vjudge.net/contest/276358#problem/B 题目大意:和上一次写叉积的题目一样,就只是线不是按照顺序给的,是乱序的,然后输出的时候是按照有三 ...

  7. Hibernate延迟加载策略

    所谓懒加载(lazy)就是延时加载,就是当在真正需要数据的时候,才真正执行数据加载操作 至于为什么要用懒加载呢,就是当我们要访问的数据量过大时,明显用缓存不太合适,因为内存容量有限 ,为了减少并发量, ...

  8. Mysql字符集介绍

  9. linux系统时间不同步解决办法(同步本地时间)

    改变/etc/目录下的localtime文件,既可以改变当前的时区 1.方法是到/usr/share/zoneinfo目录下找到你要相对应的时区文件,例如上海在/usr/share/zoneinfo/ ...

  10. 为什么要使用断路器Hystrix?

    为什么需要 Hystrix? 在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用(RPC).为了保证其高可用,单个服务又必须集群部署.由于网络原因或者自身的原因,服务并不能保证服 ...