Luogu 3350 [ZJOI2016]旅行者
BZOJ 4456
听若干个大佬讲过$n$遍终于写掉了。
我把时限基本上跑满了2333……
分治 + 最短路。
首先我们去分治这个矩形格子,找到一条长边把它对半切,对切开的边上的每一个点跑一遍最短路然后更新所有答案,接下来把询问分成两类,一类是两个端点都在切开的中间线一侧的,另一类是在两侧的。对于在中轴线一侧的点,我们把它加到一侧去继续分治,而在中轴线两侧的点就不用继续分治了,因为接下来的中轴线一定不会对它造成影响。
分治边界是没有对应询问的情况和只剩下一个点但是仍然有询问的情况,这时候可以直接用$0$更新当前的答案。
不会算时间复杂度,这篇博客证明是$O(S\sqrt{S}logS)$的,其中$S$代表面积。
另外,听说$spfa$比$dijskra$跑得快……
Code:
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
typedef pair <int, int> pin; const int N = 2e4 + ;
const int M = 1e5 + ;
const int inf = 0x3f3f3f3f; int n, m, qn, tot = , head[N], dis[N], ans[M], verx[N], very[N];
bool vis[N];
priority_queue <pin> Q; struct Edge {
int to, nxt, val;
} e[N << ]; inline void add(int from, int to, int val) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} inline void addEdge(int x, int y, int val) {
add(x, y, val), add(y, x, val);
} struct Querys {
int xa, xb, ya, yb, id;
} q[M], tmp[M]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void chkMin(int &x, int y) {
if(y < x) x = y;
} inline int id(int x, int y) {
return (x - ) * m + y;
} void dij(int xl, int xr, int yl, int yr, int stx, int sty) {
for(int i = xl; i <= xr; i++)
for(int j = yl; j <= yr; j++)
dis[id(i, j)] = inf, vis[id(i, j)] = ; dis[id(stx, sty)] = ;
Q.push(pin(, id(stx, sty)));
for(; !Q.empty(); ) {
int x = Q.top().second; Q.pop();
if(vis[x]) continue;
vis[x] = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(verx[y] >= xl && verx[y] <= xr && very[y] >= yl && very[y] <= yr) {
if(dis[y] > dis[x] + e[i].val) {
dis[y] = dis[x] + e[i].val;
Q.push(pin(-dis[y], y));
}
}
}
}
} void solve(int xl, int xr, int yl, int yr, int ql, int qr) {
if(ql > qr) return; if(xl == xr && yl == yr) {
for(int i = ql; i <= qr; i++)
chkMin(ans[q[i].id], );
return;
} if(xr - xl > yr - yl) {
int mid = ((xl + xr) >> );
for(int i = yl; i <= yr; i++) {
dij(xl, xr, yl, yr, mid, i);
for(int j = ql; j <= qr; j++) {
int x = id(q[j].xa, q[j].ya), y = id(q[j].xb, q[j].yb);
chkMin(ans[q[j].id], dis[x] + dis[y]);
}
} int l = ql - , r = qr + ;
for(int i = ql; i <= qr; i++) {
if(q[i].xa <= mid && q[i].xb <= mid) tmp[++l] = q[i];
else if(q[i].xa > mid && q[i].xb > mid) tmp[--r] = q[i];
}
for(int i = ql; i <= l; i++) q[i] = tmp[i];
for(int i = r; i <= qr; i++) q[i] = tmp[i]; solve(xl, mid, yl, yr, ql, l);
solve(mid + , xr, yl, yr, r, qr);
} else {
int mid = ((yl + yr) >> );
for(int i = xl; i <= xr; i++) {
dij(xl, xr, yl, yr, i, mid);
for(int j = ql; j <= qr; j++) {
int x = id(q[j].xa, q[j].ya), y = id(q[j].xb, q[j].yb);
chkMin(ans[q[j].id], dis[x] + dis[y]);
}
} int l = ql - , r = qr + ;
for(int i = ql; i <= qr; i++) {
if(q[i].ya <= mid && q[i].yb <= mid) tmp[++l] = q[i];
else if(q[i].ya > mid && q[i].yb > mid) tmp[--r] = q[i];
}
for(int i = ql; i <= l; i++) q[i] = tmp[i];
for(int i = r; i <= qr; i++) q[i] = tmp[i]; solve(xl, xr, yl, mid, ql, l);
solve(xl, xr, mid + , yr, r, qr);
}
} int main() {
// freopen("tourist3.in", "r", stdin);
// freopen("my.out", "w", stdout);
// freopen("Sample.txt", "r", stdin); read(n), read(m); for(int i = ; i <= n; i++)
for(int j = ; j <= m; j++)
verx[id(i, j)] = i, very[id(i, j)] = j; /* for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
printf("%d %d %d\n", id(i, j), verx[id(i, j)], very[id(i, j)]); */ for(int i = ; i <= n; i++)
for(int j = ; j < m; j++) {
int v; read(v);
addEdge(id(i, j), id(i, j + ), v);
}
for(int i = ; i < n; i++)
for(int j = ; j <= m; j++) {
int v; read(v);
addEdge(id(i, j), id(i + , j), v);
} read(qn);
for(int i = ; i <= qn; i++) {
read(q[i].xa), read(q[i].ya), read(q[i].xb), read(q[i].yb);
q[i].id = i;
} memset(ans, 0x3f, sizeof(ans));
solve(, n, , m, , qn); for(int i = ; i <= qn; i++)
printf("%d\n", ans[i]); return ;
}
Luogu 3350 [ZJOI2016]旅行者的更多相关文章
- P3350 [ZJOI2016]旅行者
题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...
- bzoj4456: [Zjoi2016]旅行者
题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...
- 4456: [Zjoi2016]旅行者
4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
[BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...
- luogu3350 [ZJOI2016]旅行者
链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...
- Luogu3350 ZJOI2016 旅行者 最短路、分治
传送门 题意:给出一个$N \times M$的网格图,边有边权,$Q$组询问,每组询问$(x_1,y_1)$到$(x_2,y_2)$的最短路.$N \times M \leq 2 \times 10 ...
- ●BOZJ 4456 [Zjoi2016]旅行者
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解: 分治好题.大致做法如下:对于一开始的矩形区域,过较长边的中点把矩形区域分为两个 ...
- [ZJOI2016]旅行者
题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...
随机推荐
- asp.net core microservices 架构之Task 事务一致性 事件源 详解
一 aspnetcore之task的任务状态-CancellationToken 我有一篇文章讲解了asp.net的线程方面的知识.我们知道.net的针对于多线程的一个亮点就是Task,net clr ...
- eclipse “”base revision” vs. “latest from repository”
base revision(基本版本):代表的是最近一次从svn服务器上面获取的版本内容:本质还是本地版本,只不过这个版本是上次从服务器上面获取的. lastest from resource(资源库 ...
- oracle11g,安装失败,提示找不到文件,win7 64位下报错
提示: 未找到文件 E:\app\Administrator\product\11.2.0\dbhome_5\owb\external\oc4j_applications\applications\W ...
- (转)oracle的split函数
本文转载自:http://www.cnblogs.com/linbaoji/archive/2009/09/17/1568252.html PL/SQL 中没有split函数,需要自己写. 代码: c ...
- keytool生成JKS证书的详细步骤及截图
注:防止有不必要的空格,尽量不要复制粘贴 1. 依据CFCA所提供的CN生成密钥存储文件和密钥对(创建JKS证书库) keytool -genkey -v -alias slserver -keyal ...
- 为工具箱添加CSKin选项卡
如何使用CSKin 项目的引用→右键→添加; 找到SCKin.dll; 添加引用 工具箱新建一个选项卡; 工具箱的空白处→右键→添加选项卡→SKinControl, 将刚才的CSKin.dll 直接拖 ...
- Python多线程-事件
线程事件用于线程控制线程,实现多个进程间的交互,线程事件的初始值为False set:将线程事件的值设为True clear:将线程事件的值设为False # -*- coding:utf-8 -*- ...
- Three.js导入gltf模型和动画
核心代码 复杂的3D模型一般都是用第三方建模工具生成,然后加载到three中 three官方推荐使用gltf格式的文件,代表编辑器是blender 本文生成了自定义生成了一个blender模型,并且应 ...
- 易混淆的Window窗体与父窗体之间位置关系
假设有abc三个窗体,a是最外层窗体,b是a的子窗体,c是b的子窗体 c.Top,c.Left,c.Bottom,c.Location等都是相对于B的左上角点的,子窗体的位置点都是相对于父窗体而言的, ...
- day4心得
装饰器: 定义:本质就是函数,(装饰其他函数)就是为其他函数添加附加功能 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 实现装饰器知识储备: 1.函数即"变量& ...