bzoj4456 [Zjoi2016]旅行者

Description

小Y来到了一个新的城市旅行。她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j≤m)。她发现不同的道路路况不同,所以通过不同的路口需要不同的时间。通过调查发现,从路口(i,j)到路口(i,j+1)需要时间 r(i,j),从路口(i,j)到路口(i+1,j)需要时间c(i,j)。注意这里的道路是双向的。小Y有q个询问,她想知道从路口(x1,y1)到路口(x2,y2)最少需要花多少时间。

Input

第一行包含 2 个正整数n,m,表示城市的大小。

接下来n行,每行包含m-1个整数,第i行第j个正整数表示从一个路口到另一个路口的时间r(i,j)。

接下来n-1行,每行包含m个整数,第i行第j个正整数表示从一个路口到另一个路口的时间c(i,j)。

接下来一行,包含1个正整数q,表示小Y的询问个数。

接下来q行,每行包含4个正整数 x1,y1,x2,y2,表示两个路口的位置。

Output

输出共q行,每行包含一个整数表示从一个路口到另一个路口最少需要花的时间。

Sample Input

2 2
2
3
6 4
2
1 1 2 2
1 2 2 1

Sample Output

6
7

HINT

题解:JudgeOnline/upload/201603/4456 sol.txt

正解:分治+$dijkstra$。

这道题的思路很神奇啊。。

直接暴力搞肯定炸,我们考虑分治。

这相当于平面上的分治,我们每次在横轴和纵轴中选择较长的那一条二分,二分出一条中轴,然后分别以中轴上每个点为起点,在当前这个矩形内跑最短路,并更新每个询问。递归分治时我们就把完全在左边的路径放到左边,完全在右边的路径放在右边。如果一条路径跨越了中轴线,那么它肯定已经求出最短路,就不用再递归了。

为了降低复杂度,我们使用手写堆,因为手写堆可以让每个结点只加入一次,$dijkstra$的复杂度就可以降低。

  1 //It is made by wfj_2048~
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <cstdio>
  7 #include <vector>
  8 #include <cmath>
  9 #include <queue>
 10 #include <stack>
 11 #include <map>
 12 #include <set>
 13 #define inf ((1<<30)-1)
 14 #define N (500010)
 15 #define il inline
 16 #define RG register
 17 #define ll long long
 18 #define pos(i,j) ((i-1)*m+j)
 19
 20 using namespace std;
 21
 22 int head[N],dis[N],ans[N],bl[N][2],n,m,num,qq;
 23
 24 struct node{ int i,lx,ly,rx,ry; }q[N],qu[N];
 25 struct edge{ int nt,to,dis; }g[N];
 26 struct heap{
 27
 28 #define fa (x>>1)
 29 #define ls (x<<1)
 30 #define rs (x<<1|1)
 31
 32     int a[N],id[N],len;
 33
 34     il void push(RG int u){
 35     if (!id[u]) id[u]=++len,a[len]=u; RG int x=id[u];
 36     while (fa){
 37         if (dis[a[x]]>=dis[a[fa]]) break;
 38         swap(a[x],a[fa]),id[a[x]]=x,id[a[fa]]=fa,x=fa;
 39     }
 40     return;
 41     }
 42
 43     il void pop(){
 44     id[a[1]]=0,a[1]=a[len--]; if (len) id[a[1]]=1; RG int x=1,son;
 45     while (ls<=len){
 46         son=(rs<=len && dis[a[rs]]<dis[a[ls]]) ? rs : ls;
 47         if (dis[a[x]]<=dis[a[son]]) break;
 48         swap(a[x],a[son]),id[a[x]]=x,id[a[son]]=son,x=son;
 49     }
 50     return;
 51     }
 52
 53 #undef fa
 54 #undef ls
 55 #undef rs
 56
 57 }Q;
 58
 59 il int gi(){
 60     RG int x=0,q=1; RG char ch=getchar();
 61     while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar();
 62     if (ch==‘-‘) q=-1,ch=getchar();
 63     while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar();
 64     return q*x;
 65 }
 66
 67 il void insert(RG int from,RG int to,RG int dis){
 68     g[++num]=(edge){head[from],to,dis},head[from]=num; return;
 69 }
 70
 71 il void dijkstra(RG int lx,RG int rx,RG int ly,RG int ry,RG int inix,RG int iniy){
 72     for (RG int i=lx;i<=rx;++i)
 73     for (RG int j=ly;j<=ry;++j) dis[pos(i,j)]=inf;
 74     dis[pos(inix,iniy)]=0,Q.push(pos(inix,iniy));
 75     while (Q.len){
 76     RG int x=Q.a[1],v,nowx,nowy; Q.pop();
 77     for (RG int i=head[x];i;i=g[i].nt){
 78         v=g[i].to,nowx=bl[v][0],nowy=bl[v][1];
 79         if (nowx<lx || nowx>rx || nowy<ly || nowy>ry) continue;
 80         if (dis[v]>dis[x]+g[i].dis) dis[v]=dis[x]+g[i].dis,Q.push(v);
 81     }
 82     }
 83     return;
 84 }
 85
 86 il void solve(RG int lx,RG int rx,RG int ly,RG int ry,RG int l,RG int r){
 87     if (lx>rx || ly>ry || l>r) return;
 88     if (l==r){
 89     dijkstra(lx,rx,ly,ry,q[l].lx,q[l].ly);
 90     ans[q[l].i]=min(ans[q[l].i],dis[pos(q[l].rx,q[l].ry)]);
 91     return;
 92     }
 93     RG int mid,t1=l-1,t2=r+1;
 94     if (rx-lx>=ry-ly){
 95     mid=(lx+rx)>>1;
 96     for (RG int y=ly;y<=ry;++y){
 97         dijkstra(lx,rx,ly,ry,mid,y);
 98         for (RG int i=l;i<=r;++i)
 99         ans[q[i].i]=min(ans[q[i].i],dis[pos(q[i].lx,q[i].ly)]+dis[pos(q[i].rx,q[i].ry)]);
100     }
101     for (RG int i=l;i<=r;++i)
102         if (q[i].lx<mid && q[i].rx<mid) qu[++t1]=q[i];
103         else if (q[i].lx>mid && q[i].rx>mid) qu[--t2]=q[i];
104     for (RG int i=l;i<=t1;++i) q[i]=qu[i];
105     for (RG int i=r;i>=t2;--i) q[i]=qu[i];
106     solve(lx,mid,ly,ry,l,t1),solve(mid+1,rx,ly,ry,t2,r);
107     } else{
108     mid=(ly+ry)>>1;
109     for (RG int x=lx;x<=rx;++x){
110         dijkstra(lx,rx,ly,ry,x,mid);
111         for (RG int i=l;i<=r;++i)
112         ans[q[i].i]=min(ans[q[i].i],dis[pos(q[i].lx,q[i].ly)]+dis[pos(q[i].rx,q[i].ry)]);
113     }
114     for (RG int i=l;i<=r;++i)
115         if (q[i].ly<mid && q[i].ry<mid) qu[++t1]=q[i];
116         else if (q[i].ly>mid && q[i].ry>mid) qu[--t2]=q[i];
117     for (RG int i=l;i<=t1;++i) q[i]=qu[i];
118     for (RG int i=r;i>=t2;--i) q[i]=qu[i];
119     solve(lx,rx,ly,mid,l,t1),solve(lx,rx,mid+1,ry,t2,r);
120     }
121     return;
122 }
123
124 int main(){
125 #ifndef ONLINE_JUDGE
126     freopen("tourist.in","r",stdin);
127     freopen("tourist.out","w",stdout);
128 #endif
129     n=gi(),m=gi();
130     for (RG int i=1;i<=n*m;++i) bl[i][0]=(i-1)/m+1,bl[i][1]=(i-1)%m+1;
131     for (RG int i=1;i<=n;++i)
132     for (RG int j=1,w;j<m;++j)
133         w=gi(),insert(pos(i,j),pos(i,j+1),w),insert(pos(i,j+1),pos(i,j),w);
134     for (RG int i=1;i<n;++i)
135     for (RG int j=1,w;j<=m;++j)
136         w=gi(),insert(pos(i,j),pos(i+1,j),w),insert(pos(i+1,j),pos(i,j),w);
137     qq=gi();
138     for (RG int i=1;i<=qq;++i)
139     q[i].i=i,q[i].lx=gi(),q[i].ly=gi(),q[i].rx=gi(),q[i].ry=gi(),ans[i]=inf<<1;
140     solve(1,n,1,m,1,qq); for (RG int i=1;i<=qq;++i) printf("%d\n",ans[i]);
141     return 0;
142 }
时间: 2024-10-10 02:21:30

bzoj4456 [Zjoi2016]旅行者的相关文章

【BZOJ4456】 [Zjoi2016]旅行者 / 【UOJ #184】 【ZJOI2016】旅行者

Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北 的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j≤m).她发现不同的道路路况不同,所以通过不 同的路口需要不同的时间.通过调查发现,从路口(i,j)到路口(i,j+1)需要时间 r(i,j),从路口(i,j)到路口(i+1 ,j)需要时间c(i,j).注意这里的道路是双向的.小Y有q个询问,她想知道从路口(x1,y1)到路口(x2,y2)最少需要

ZJOI2018酱油记

ZJOI2018酱油记 前言 作为\(HN\)高一蒟蒻选手,毕竟去了趟\(ZJOI\)玩泥巴 不写点游记还是不太好吧. 今天来补一补. Day0 星期天,中午,我们一群人滚到了学校门口 然后集合,滚去坐地铁连校车都不提供,差评 高铁站感觉很久很久很久没有来过了 换句话说,我很久很久很久没有离开过长沙了 忽然出去一趟,似乎也挺爽的. 在车上,拿出电脑打了几句红警,一个人玩好无聊 然后在车厢里漫无目的的游走,顺便%%%雅礼的巨佬们 下午到了衢州, 跟长沙一比较, 长沙果然是省会城市啊,光是看一眼就能

【ZJOI2016】旅行者

题面 https://www.luogu.org/problem/P3350 网格图上最短路 题解 离线+分治. 最短路两种情况,穿过中间边和没穿过中间边. 对于当前区域包含的询问: 先找当前区域中间边(尽可能切成正方形) 对中间边上的点,求当前区域内所有的点对其的最短路. 如果两点被中间边切断,那这次一定能得到最优解,可以去掉. 如果两点没被中间边切断,递归下去. // luogu-judger-enable-o2 #include<cstdio> #include<cstring&g

黯淡蓝点:旅行者号64亿公里外回望地球...

1990年“旅行者”号探测器在即将飞出太阳系的时候,最后一次回眸我们的家园--地球! “旅行者”号探测器从40亿英里(约64亿公里)之外拍摄了上面两张地球照片.第一张照片中,地球仅是一个0.12个像素大小的圆点.著名天文学家卡尔·萨根将其描绘成“硕大的宇宙夜幕中一个孤独的圆点,对我来说,它强调了我们在更友善.更积极地处理相互之间的关系上的责任,以及保护和爱惜这个黯淡蓝点的责任,这是人类已知的唯一家园.” 地球是在这个浩翰宇宙剧院里的一个细小舞台. 想想从那些将令们和皇帝们溢出的血河,他们的光荣与

【NOIP考前模拟赛】纯数学方法推导——旅行者问题

一.写在前面 这题似乎是一道原创题目(不是博主原创),所以并不能在任何OJ上评测,博主在网盘上上传了数据(网盘地址:http://pan.baidu.com/s/1mibdMXi),诸位看官需者自取.另外博主使用此题并没有获得出题人授权,如果出题人看到这篇blog并认为在下侵犯了您的权利,请用站内消息与在下联系,在下会立即删除这篇blog,给您带来的困扰之处敬请谅解. 博主上传这道题主要是因为这题牵扯许多数学运算,推导过程比较复杂,但是却没有用到任何算法或者数学定理,可以说这是一道想法题的典范.

NOIP模拟赛-旅行者问题 解题报告

题目 :http://www.tsinsen.com/P9143 题是我发现.想测可以测.已经分享出去了. 旅行者问题 [问题描述] lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行.lahub想去参观n个目的地(都在一条直道上).lahub在起点开始他的旅行.第i个目的地和起点的距离为ai千米(ai为非负整数).不存在两个目的地和起点的距离相同. 从第i个目的地走到第j个目的地所走的路程为 |ai-aj|千米.我们把参观n个目的地的顺序称作一次“旅行”.lahub

ZJOI2016

首先做了T2的旅行者,看到bz上面过的人数比较多.. 考试的时候完全没有想太多.一闪而过了分块思想,然后就没有然后了.. 大视野上面有题解,竟然是一个初中生写的..? 正解其实是“分治”,每次选择中轴线,不会势能分析,感觉考场上想出来也肯定不敢打.. #include<cstdio> #include<algorithm> #define inf 1000000000 #define N 100010 using namespace std; int dis[N],ans[N],q

4455[Zjoi2016]小星星 容斥+dp

4455: [Zjoi2016]小星星 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 527  Solved: 317[Submit][Status][Discuss] Description 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细 线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了n?1条细线,但 通过这些细线,这颗小星星还是被串在一起,也就是这

uoj #185. 【ZJOI2016】小星星

#185. [ZJOI2016]小星星 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有 nn 颗小星星,用 mm 条彩色的细线串了起来,每条细线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了 n−1n−1 条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树. 小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星.如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上