BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)
\(Description\)
给定\(n\times m\)的带边权网格图。\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路。
\(n\times m\leq 2\times 10^4,Q\leq 10^5\).
\(Solution\)
对分治线上的每个点进行一次Dijkstra。若该区域点数(面积)为S,则分治线如果选择较短的一边,其上点的个数\(\leq\sqrt S\)。每次选较短的分治复杂度\(O(S\sqrt S\log S)\),若不这样复杂度\(O(S\sqrt S\log^2 S)\)。(\(T(n)=T(\frac{n}{2})+O(S\sqrt S\log S)=O(S\sqrt S\log S)\)?网上题解有证明。)
若一次询问的\((x,y)\)在分治线两侧,则可以枚举分治线上的点\(i\)用\(\min\{dis_{i,x}+dis_{i,y}\}\)更新答案,然后删掉这个询问;若\((x,y)\)在分治线同侧,则也用\(\min\{dis_{i,x}+dis_{i,y}\}\)更新一次过分治线的答案,继续分治。
//5804kb 18088ms
//怎么这么慢啊。。赋值也比调用快么。。
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 400000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define ID(x,y) ((x-1)*m+y)
#define mp std::make_pair
#define pr std::pair<int,int>
const int N=2e4+5,M=1e5+5,Way[5]={0,-1,0,1,0};
int n,m,val[N][4],dis[N],Ans[M],seq[M],tmp[M],X[N],Y[N];//0:left 1:up 2:right 3:down
char IN[MAXIN],*SS=IN,*TT=IN;
struct Queries
{
int xa,xb,ya,yb,x,y,id;
}q[M];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void Dijkstra(int s,int xa,int ya,int xb,int yb)
{
static int Time,vis[N],upd[N];
static std::priority_queue<pr> q;
upd[s]=++Time, q.push(mp(dis[s]=0,s));
while(!q.empty())
{
int now=q.top().second;
q.pop();
if(vis[now]==Time) continue;
vis[now]=Time;
// int x=(now-1)/m+1, y=now%m; if(!y) y=m;
int x=X[now], y=Y[now];
for(int v,xn,yn,i=0; i<4; ++i)
{
if((xn=x+Way[i])<xa||xn>xb||(yn=y+Way[i+1])<ya||yn>yb) continue;
if((upd[v=ID(xn,yn)]!=Time&&(upd[v]=Time))/*初始值INF*/||dis[v]>dis[now]+val[now][i])
q.push(mp(-(dis[v]=dis[now]+val[now][i]),v));
}
}
}
void Solve(int xa,int ya,int xb,int yb,int l,int r)
{
if(xa>xb||ya>yb||l>r) return;
if(xb-xa<=yb-ya)
{
int mid=ya+yb>>1;
for(int i=xa; i<=xb; ++i)
{
Dijkstra(ID(i,mid),xa,ya,xb,yb);
for(int id,j=l; j<=r; ++j)
id=seq[j], Ans[q[id].id]=std::min(Ans[q[id].id],dis[q[id].x]+dis[q[id].y]);
}
int nowl=l, nowr=r;
for(int id,i=l; i<=r; ++i)
if(q[id=seq[i]].ya<mid && q[id].yb<mid) tmp[nowl++]=id;
else if(q[id].ya>mid && q[id].yb>mid) tmp[nowr--]=id;
for(int i=l; i<nowl; ++i) seq[i]=tmp[i];
for(int i=nowr+1; i<=r; ++i) seq[i]=tmp[i];
Solve(xa,ya,xb,mid-1,l,nowl-1), Solve(xa,mid+1,xb,yb,nowr+1,r);
}
else
{
int mid=xa+xb>>1;
for(int i=ya; i<=yb; ++i)
{
Dijkstra(ID(mid,i),xa,ya,xb,yb);
for(int id,j=l; j<=r; ++j)
id=seq[j], Ans[q[id].id]=std::min(Ans[q[id].id],dis[q[id].x]+dis[q[id].y]);
}
int nowl=l, nowr=r;
for(int id,i=l; i<=r; ++i)
if(q[id=seq[i]].xa<mid && q[id].xb<mid) tmp[nowl++]=id;
else if(q[id].xa>mid && q[id].xb>mid) tmp[nowr--]=id;
for(int i=l; i<nowl; ++i) seq[i]=tmp[i];
for(int i=nowr+1; i<=r; ++i) seq[i]=tmp[i];
Solve(xa,ya,mid-1,yb,l,nowl-1), Solve(mid+1,ya,xb,yb,nowr+1,r);
}
}
int main()
{
n=read(), m=read();
for(int i=1,tot=1; i<=n; ++i,++tot)
for(int j=1; j<m; ++j,++tot) val[tot][2]=val[tot+1][0]=read();
for(int i=1,tot=1; i<n; ++i)
for(int j=1; j<=m; ++j,++tot) val[tot][3]=val[tot+m][1]=read();
for(int i=1,tot=1; i<=n; ++i)
for(int j=1; j<=m; ++j,++tot) X[tot]=i, Y[tot]=j;
memset(Ans,0x3f,sizeof Ans);
int Q=read();
for(int i=1,xa,ya,xb,yb; i<=Q; ++i)
{
xa=read(), ya=read(), xb=read(), yb=read();
// if(xa==xb && ya==yb) Ans[i]=0;
seq[i]=i, q[i]=(Queries){xa,xb,ya,yb,ID(xa,ya),ID(xb,yb),i};
}
Solve(1,1,n,m,1,Q);
for(int i=1; i<=Q; ++i) printf("%d\n",Ans[i]);
return 0;
}
BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)的更多相关文章
- bzoj 4456 [Zjoi2016]旅行者
题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解 分治 设当前work的区间为(x1,y1,x2,y2) 我们将长边分成两半 不妨 ...
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- 4456: [Zjoi2016]旅行者
4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
[BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...
- ●BOZJ 4456 [Zjoi2016]旅行者
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解: 分治好题.大致做法如下:对于一开始的矩形区域,过较长边的中点把矩形区域分为两个 ...
- BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路
原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html 题目传送门 - BZOJ4456 题目传送门 - UOJ#184 题意 $n\times ...
- 【BZOJ-4456】旅行者 分治 + 最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 254 Solved: 162[Submit][Status] ...
- P3350 [ZJOI2016]旅行者
题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...
- bzoj4456: [Zjoi2016]旅行者
题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...
随机推荐
- java字符数组char[]和字符串String之间的转换
java字符数组char[]和字符串String之间的转换 觉得有用的话,欢迎一起讨论相互学习~Follow Me 使用String.valueOf()将字符数组转换成字符串 void (){ cha ...
- 设置 Linux 服务器中 MySQL 允许远程访问
开启 MySQL 远程访问权限: 在linux系统上登陆mysql服务. -- root 是用户名 [root@localhost ~]# mysql -u root -p Enter passwor ...
- SQL记录-PLSQL触发器
PL/SQL触发器 触发器是存储程序,它会自动执行或发射当一些事件发生.触发器,事实上,写入响应于以下任一事件将被执行: 数据库操作(DML)语句(DELETE,INSERT,UPDATE或) 数据库 ...
- Stochastic Optimization Techniques
Stochastic Optimization Techniques Neural networks are often trained stochastically, i.e. using a me ...
- Java SSM框架之MyBatis3(八)MyBatis之动态SQL
前言: mybatis框架中最具特色的便是sql语句中的自定义,而动态sql的使用又使整个框架更加灵活. 创建User表 /*Table structure for table `user` */ D ...
- [转载]微软VS2015支持Android和iOS编程
Visual Studio 2015 Preview http://www.zhihu.com/question/26594936/answer/33397319 http://www.visuals ...
- MySQL ODBC 驱动安装
一.在线安装 1.yum在线安装驱动 # yum -y install unixODBC # yum -y install mysql-connector-odbc 2.配置驱动 (1)查看驱动程序相 ...
- Linux输出重定向>和>>的区别是什么
[简介:>与>>的区别] 1 > 是定向输出到文件,如果文件不存在,就创建文件:如果文件存在,就将其清空:一般我们备份清理日志文件的时候,就是这种方法:先备份日志,再用`& ...
- sublime sftp 打开远程文件夹
2014-04-29 13:19:09 总结: 本文介绍两种方法,推荐第二种方法(samba+windows映射) 先贴出sublime打开远程(Linux)目录所需的配置文件(sublime是通过s ...
- nginx:在centos中自启动
参考网址:http://www.jb51.net/article/120545.htm # vi /etc/init.d/nginx #!/bin/sh # Name:nginx4comex # ng ...