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]旅行者的更多相关文章

  1. P3350 [ZJOI2016]旅行者

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

  2. bzoj4456: [Zjoi2016]旅行者

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

  3. 4456: [Zjoi2016]旅行者

    4456: [Zjoi2016]旅行者 https://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. 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路

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

  6. luogu3350 [ZJOI2016]旅行者

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

  7. Luogu3350 ZJOI2016 旅行者 最短路、分治

    传送门 题意:给出一个$N \times M$的网格图,边有边权,$Q$组询问,每组询问$(x_1,y_1)$到$(x_2,y_2)$的最短路.$N \times M \leq 2 \times 10 ...

  8. ●BOZJ 4456 [Zjoi2016]旅行者

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

  9. [ZJOI2016]旅行者

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

随机推荐

  1. HWOJ-合唱队

    计算最少出列多少位同学,使得剩下的同学排成合唱队形 说明: N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依 ...

  2. 学习动态性能表(3)--v$sql&v$sql_plan

    学习动态性能表 第三篇-(1)-v$sq 2007.5.25 V$SQL中存储具体的SQL语句. 一条语句可以映射多个cursor,因为对象所指的cursor可以有不同用户(如例1).如果有多个cur ...

  3. iis部署网页时应该避免的特殊端口

    1 tcpmux 7 echo 9 discard 11 systat 13 daytime 15 netstat 17 qotd 19 chargen 20 ftp data 21 ftp cont ...

  4. Java开发过程中乱码问题理解

    1.Java编译器(即编译成class文件时) 用的是unicode字符集.2.乱码主要是由于不同的字符集相互转换导致的,理论上各个字符的编码规则是不同的,是不能相互转换的,所以根本解决乱码的方法就是 ...

  5. android资源目录---assets与res/raw区别

    android资源目录---assets与res/raw的不同 Android 2011-05-24 14:40:21 阅读20 评论0   字号:大中小 订阅 assets:用于存放需要打包到应用程 ...

  6. 【转】学习使用Jmeter做压力测试(三)--数据库测试

    JMeter可以做为Web服务器与浏览器之间的代理网关,以捕获浏览器的请求和Web服务器的响应,这样就可很容易的生成性能测试脚本.根据脚本,JMeter可通过线程组来模拟真实用户对Web服务器做压力测 ...

  7. 小程序App方法

    App() 注册一个小程序 小程序的入口方法 //app.js App({ onLaunch: function(options) { console.log("onLaunch" ...

  8. form表单使用(博客系统的登陆验证,注册)

    先从小的实例来看form的用法 登陆验证实例,来看form的常规用法 1. forms.py # 用于登陆验证验证 from django.core.validators import RegexVa ...

  9. 解决阿里云下server 2008中tomcat不能外网访问

    1. 首先这台服务器是别人给到手的服务器, 所有环境跟我讲是全新的, 然后我开始配置tomcat; 开始安装sql 2008 r22. r1安装好之后, 本机内部怎么访问都行( . 和 127.0.0 ...

  10. PHP字符串的处理(三)-字符串的输出

    1.echo() echo()实际不是一个函数,是一个语言结构,不需要使用括号 <?php $str = "test"; echo $str."<br> ...