4456: [Zjoi2016]旅行者

https://www.lydsy.com/JudgeOnline/problem.php?id=4456

分析:

  每次对当前矩阵按长边化一条分治线,然后在对分治线上的点跑最短路,然后可以处理处过分治线的询问。对于不过分治线的,递归处理。

  先写的dijkstra+堆优化,在开O2的情况下可以过,不开O2过不了,卡常~,还是过不了。然后在UOJ的排行榜里(而且UOJ是有大样例的!),看到了两个优化,加上就可以了。

  优化:1、代码41行,用上次的遍历结果初始化。2、将dijkstra改成spfa+SLF优化。

代码:

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long LL; char buf[],*_p1 = buf,*_p2 = buf;
#define nc() (_p1==_p2&&(_p2=(_p1=buf)+fread(buf,1,100000,stdin),_p1==_p2) ? EOF :*_p1++)
inline int read() {
int x=,f=;char ch=nc();for(;!isdigit(ch);ch=nc())if(ch=='-')f=-;
for (;isdigit(ch);ch=nc())x=x*+ch-'';return x*f;
} #define getid(a,b) ((a - 1) * m + b)
#define pa pair<int,int>
#define mp(a,b) make_pair(a,b) const int INF = 1e9;
const int N = ; struct Que{
int a1,b1,a2,b2,id;
}A[N], B[N];
int dis[N], ans[N], head[N], nxt[N], to[N], len[N];
int n, m, En;
//priority_queue< pa, vector< pa >, greater< pa > > q; // 这才是小根堆!!!
int q[];
bool vis[N]; inline void getxy(int id,int &x,int &y) {
x = (id - ) / m + ;
y = (id - ) % m + ;
}
void dijkstra(int s,int a1,int a2,int b1,int b2,int h) {
int x, y, d = dis[s];
for (int i=a1; i<=a2; ++i)
for (int j=b1; j<=b2; ++j) {
x = getid(i, j);
dis[x] = h ? dis[x] + d : INF;
vis[x] = false;
}
dis[s] = ;
/* q.push(mp(dis[s], s));
while (!q.empty()) {
pa now = q.top(); q.pop();
int u = now.second;
if (vis[u]) continue;
vis[u] = true;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
getxy(v, x, y);
if (x >= a1 && x <= a2 && y >= b1 && y <= b2 && dis[v] > dis[u] + len[i]) {
dis[v] = dis[u] + len[i];
q.push(mp(dis[v], v));
}
}
}*/
int L = , R = L - ;
q[++R] = s;vis[s] = true;
while (L <= R) {
int u = q[L ++];vis[u] = false;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
getxy(v, x, y);
if (x >= a1 && x <= a2 && y >= b1 && y <= b2 && dis[v] > dis[u] + len[i]) {
dis[v] = dis[u] + len[i];
if (!vis[v]) {
if (dis[v] <= dis[q[L]]) q[--L] = v;
else q[++R] = v;
vis[v] = true;
}
}
}
}
}
void solve(int a1,int a2,int b1,int b2,int L,int R) {
if (L > R) return ;
int i, j, k;
if (a2 - a1 > b2 - b1) {
int mid = (a2 + a1) / ; // a2 + a1
for (i=b1; i<=b2; ++i) {
dijkstra(getid(mid, i), a1, a2, b1, b2, i-b1);
for (j=L; j<=R; ++j)
ans[A[j].id] = min(ans[A[j].id], dis[getid(A[j].a1, A[j].b1)] + dis[getid(A[j].a2, A[j].b2)]);
}
i = L - , j = R + ;
for (k=L; k<=R; ++k) {
if (A[k].a1 < mid && A[k].a2 < mid) B[++i] = A[k];
if (A[k].a1 > mid && A[k].a2 > mid) B[--j] = A[k];
}
for (k=L; k<=i; ++k) A[k] = B[k]; solve(a1, mid-, b1, b2, L, i);
for (k=j; k<=R; ++k) A[k] = B[k]; solve(mid+, a2, b1, b2, j, R);
}
else {
int mid = (b2 + b1) / ;
for (i=a1; i<=a2; ++i) {
dijkstra(getid(i, mid), a1, a2, b1, b2, i-a1);
for (j=L; j<=R; ++j)
ans[A[j].id] = min(ans[A[j].id], dis[getid(A[j].a1, A[j].b1)] + dis[getid(A[j].a2, A[j].b2)]);
}
i = L - , j = R + ;
for (k=L; k<=R; ++k) {
if (A[k].b1 < mid && A[k].b2 < mid) B[++i] = A[k];
if (A[k].b1 > mid && A[k].b2 > mid) B[--j] = A[k];
}
for (k=L; k<=i; ++k) A[k] = B[k]; solve(a1, a2, b1, mid-, L, i);
for (k=j; k<=R; ++k) A[k] = B[k]; solve(a1, a2, mid+, b2, j, R);
}
}
inline void add_edge(int u,int v,int w) {
++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En;
++En; to[En] = u; len[En] = w; nxt[En] = head[v]; head[v] = En;
}
int main() {
n = read(), m = read();
for (int i=; i<=n; ++i) {
for (int j=; j<m; ++j) {
int a = read();
add_edge(getid(i, j), getid(i, j + ), a);
}
}
for (int i=; i<n; ++i) {
for (int j=; j<=m; ++j) {
int a = read();
add_edge(getid(i, j), getid(i + , j), a);
}
}
int Case = read();
for (int a,b,i=; i<=Case; ++i) {
A[i].a1 = read(), A[i].b1 = read();
A[i].a2 = read(), A[i].b2 = read();
A[i].id = i; ans[i] = INF;
}
solve(, n, , m, , Case);
for (int i=; i<=Case; ++i) printf("%d\n",ans[i]);
return ;
}

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

  1. ●BOZJ 4456 [Zjoi2016]旅行者

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

  2. bzoj 4456 [Zjoi2016]旅行者

    题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解 分治 设当前work的区间为(x1,y1,x2,y2) 我们将长边分成两半 不妨 ...

  3. BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)

    题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...

  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. luogu3350 [ZJOI2016]旅行者

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

  9. Luogu 3350 [ZJOI2016]旅行者

    BZOJ 4456 听若干个大佬讲过$n$遍终于写掉了. 我把时限基本上跑满了2333…… 分治 + 最短路. 首先我们去分治这个矩形格子,找到一条长边把它对半切,对切开的边上的每一个点跑一遍最短路然 ...

随机推荐

  1. 转 C++11 并发指南std::condition_variable详解

    之前看过,但是一直没有怎么用就忘了,转一篇别人的文字记录下来 本文将介绍 C++11 标准中 <condition_variable> 头文件里面的类和相关函数. <conditio ...

  2. QT信号和槽在哪个线程执行问题

    时隔四个月后的第一篇,换了个公司可以登录的博客,记录一些学习内容吧 这是看到别人写的比较好的一篇,排版有点乱 QThread的使用方法 起源 昨天不小心看到Qt开发人员( Bradley T.Hugh ...

  3. 当你的Spring IOC 容器(即applicationContext.xml文件)忘记配到web.xml 文件中时

    当你的Spring IOC 容器忘记配到web.xml 文件中时,启动服务器就会报错. 部分错误如下: Caused by: org.springframework.beans.factory.NoS ...

  4. 使用ViewPager和FragmentPagerAdapter实现Tab

    前面我们分别利用ViewPager和Fragment实现了Tab效果.但是使用Fragment实现的Tab不能够左右滑动.如果我们既想使用Fragment又想让Tab能够滑动,那么怎么办呢?这 就是今 ...

  5. Python小技巧:使用*解包和itertools.product()求笛卡尔积

    [问题] 目前有一字符串s = "['a', 'b'],['c', 'd']",想把它分开成为两个列表: list1 = ['a', 'b'] list2 = ['c', 'd'] ...

  6. Ubuntu中为Eclipse添加桌面启动快捷方式

    Ubuntu中应用程序启动器“XXX.desktop”还没有被标记为可信任的问题:http://www.tuicool.com/articles/fIBJ32n eclipse问题:prefences ...

  7. 三.Shell脚本提取文件名称和所在的目录

    一·简介 提取文件名称或者目录,一般都会使用到#,##,%和%%,但是他们的区别很容易记混淆了.在一下4种方式中,目标匹配字符是不在结果中. #:表示从左开始算起,并且截取第一个匹配的字符 ##:表示 ...

  8. C/C++心得-从内存开始

    因工作与自身各方面需要,开始重新学C,其实说重新也不太准,原来只是大学里面接触过,且还未得多少精髓就转其他开发,不过也正是因此才有了重新学习的必要,基础部分的心得将通过博文记录下来,对于初学者应该有些 ...

  9. 虚拟机Centos安装docker小记

    本书记录是参考 <Spring Cloud 与 Docker 微服务架构实战(第二版)>这本书实现的. 记录简单几个命令,安装顺序如下: 1. 安装docker所需的包 sudo yum ...

  10. ssm框架基本流程

    题目,写的有点大了,其实就是 对一张表的基本处理,增删改查的基本操作演示. 好了,我们开始了. 假如,我们在做一个单表处理,就举例是 学院(某个大学的学院) 吧. 首先,我们分析 学校这样表有哪些属性 ...