传送门

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


BZOJ原题竟然没有数据范围

矩形的多组询问问题考虑分治。考虑计算矩形$(x_1,y_1,x_2,y_2)$的询问,我们将较长边沿着中线劈成两半,在这些询问里面就只可能存在两种情况:①询问的两个端点在中线两边,那么路径就一定会经过中线上一点;②询问的两个端点在中线的同一边,那么有可能不会经过中线,也有可能经过中线。所以我们对中线上所有的点跑一边整个矩形的最短路,每一次跑完最短路就更新所有的询问,然后再递归进入两侧矩形回答②类型的询问。时间复杂度似乎是$O(NM \times \sqrt{NM} \times log(NM))$

在$Luogu$题解上学到的一个加速方法:从一个点的最短路转移到新的点跑最短路的时候,可以不将最短路数组赋值为极大值,而是赋值为这一个点经过上一个计算的点到达所有目标点的答案。

(然而还是在Luogu不开O2的情况下TLE)

  1 // luogu-judger-enable-o2
  2 //This code is written by Itst
  3 #include<bits/stdc++.h>
  4 #define pos(i,j) ((i-1)*M+j)
  5 using namespace std;
  6
  7 inline int read(){
  8     int a = 0;
  9     bool f = 0;
 10     char c = getchar();
 11     while(c != EOF && !isdigit(c)){
 12         if(c == '-')
 13             f = 1;
 14         c = getchar();
 15     }
 16     while(c != EOF && isdigit(c)){
 17         a = (a << 3) + (a << 1) + (c ^ '0');
 18         c = getchar();
 19     }
 20     return f ? -a : a;
 21 }
 22
 23 const int MAXN = 100010;
 24 int cntEd , N , M , Q , minDis[MAXN] , ans[MAXN] , head[MAXN];
 25 struct Edge{
 26     int end , upEd , w;
 27 }Ed[MAXN << 2];
 28 struct query{
 29     int sx , sy , ex , ey , ind;
 30 }now[MAXN] , pot[MAXN];
 31 priority_queue < pair < int , int > > q;
 32
 33 inline void addEd(int a , int b , int c){
 34     Ed[++cntEd].end = b;
 35     Ed[cntEd].w = c;
 36     Ed[cntEd].upEd = head[a];
 37     head[a] = cntEd;
 38 }
 39
 40 void Dijk(int bx , int by , int lx , int ly , int rx , int ry , int l){
 41     int temp = minDis[pos(bx , by)];
 42     for(int i = lx ; i <= rx ; i++)
 43         for(int j = ly ; j <= ry ; j++)
 44             minDis[pos(i , j)] = l == 0 ? 0x3f3f3f3f : minDis[pos(i , j)] + temp;
 45     minDis[pos(bx , by)] = 0;
 46     q.push(make_pair(0 , pos(bx , by)));
 47     while(!q.empty()){
 48         pair < int , int > t = q.top();
 49         q.pop();
 50         if(minDis[t.second] != -t.first)
 51             continue;
 52         for(int i = head[t.second] ; i ; i = Ed[i].upEd)
 53             if(minDis[Ed[i].end] > minDis[t.second] + Ed[i].w){
 54                 minDis[Ed[i].end] = minDis[t.second] + Ed[i].w;
 55                 q.push(make_pair(-minDis[Ed[i].end] , Ed[i].end));
 56             }
 57     }
 58 }
 59
 60 void solve(int lx , int ly , int rx , int ry , int ql , int qr){
 61     if(ql > qr)
 62         return;
 63     if(rx - lx > ry - ly){
 64         int mid = lx + rx >> 1;
 65         for(int i = ly ; i <= ry ; i++){
 66             Dijk(mid , i , lx , ly , rx , ry , i - ly);
 67             for(int j = ql ; j <= qr ; j++)
 68                 ans[now[j].ind] = min(ans[now[j].ind] , minDis[pos(now[j].sx , now[j].sy)] + minDis[pos(now[j].ex , now[j].ey)]);
 69         }
 70         int p1 = ql , p2 = qr;
 71         for(int i = ql ; i <= qr ; i++)
 72             if(now[i].sx < mid && now[i].ex < mid)
 73                 pot[p1++] = now[i];
 74             else
 75                 if(now[i].sx > mid && now[i].ex > mid)
 76                     pot[p2--] = now[i];
 77         memcpy(now + ql , pot + ql , sizeof(query) * (qr - ql + 1));
 78         solve(lx , ly , mid , ry , ql , p1 - 1);
 79         solve(mid + 1 , ly , rx , ry , p2 + 1 , qr);
 80     }
 81     else{
 82         int mid = ly + ry >> 1;
 83         for(int i = lx ; i <= rx ; i++){
 84             Dijk(i , mid , lx , ly , rx , ry , i - lx);
 85             for(int j = ql ; j <= qr ; j++)
 86                 ans[now[j].ind] = min(ans[now[j].ind] , minDis[pos(now[j].sx , now[j].sy)] + minDis[pos(now[j].ex , now[j].ey)]);
 87         }
 88         int p1 = ql , p2 = qr;
 89         for(int i = ql ; i <= qr ; i++)
 90             if(now[i].sy < mid && now[i].ey < mid)
 91                 pot[p1++] = now[i];
 92             else
 93                 if(now[i].sy > mid && now[i].ey > mid)
 94                     pot[p2--] = now[i];
 95         memcpy(now + ql , pot + ql , sizeof(query) * (qr - ql + 1));
 96         solve(lx , ly , rx , mid , ql , p1 - 1);
 97         solve(lx , mid + 1 , rx , ry , p2 + 1 , qr);
 98     }
 99 }
100
101 int main(){
102 #ifdef LG
103     freopen("3350.in" , "r" , stdin);
104     freopen("3350.out" , "w" , stdout);
105 #endif
106     memset(ans , 0x3f , sizeof(ans));
107     N = read();
108     M = read();
109     for(int i = 1 ; i <= N ; i++)
110         for(int j = 1 ; j < M ; j++){
111             int t = read();
112             addEd(pos(i , j) , pos(i , j + 1) , t);
113             addEd(pos(i , j + 1) , pos(i , j) , t);
114         }
115     for(int i = 1 ; i < N ; i++)
116         for(int j = 1 ; j <= M ; j++){
117             int t = read();
118             addEd(pos(i , j) , pos(i + 1 , j) , t);
119             addEd(pos(i + 1 , j) , pos(i , j) , t);
120         }
121     Q = read();
122     for(int i = 1 ; i <= Q ; i++){
123         now[i].sx = read();
124         now[i].sy = read();
125         now[i].ex = read();
126         now[i].ey = read();
127         now[i].ind = i;
128     }
129     solve(1 , 1 , N , M , 1 , Q);
130     for(int i = 1 ; i <= Q ; i++)
131         printf("%d\n" , ans[i]);
132     return 0;
133 }

转载于:https://www.cnblogs.com/Itst/p/9879787.html

Luogu3350 ZJOI2016 旅行者 最短路、分治相关推荐

  1. [ZJOI2016]旅行者(网格图分治最短路)

    problem luogu-P3350 solution 据说,网格图最短路用分治是一个人人皆知的套路.对不起我不是人 类比整体二分的算法流程. 考虑在一个 (xl,yl)−(yl,yr)(xl,yl ...

  2. BZOJ2407:探险/BZOJ4398:福慧双修-最短路+分治

    两道都是权限题- 题意: 给出一张n个点,m条边的图,同一条边不能走两次,每条边正着走与反着走所需要的时间可能不同,求一个从1开始的大于一个点的最短环 N<=10000,M<=200000 ...

  3. 51nod2943 旅行者

    2943 旅行者 题目详情见[ZJOI2016]旅行者 这里就不放代码和分析

  4. ZJOI2018游记Round1

    广告 ZJOI2018Round2游记 All Falls Down 非常感谢学弟学妹们捧场游记虽然这是一篇假游记 ZJOI Round1今天正式落下帷幕.在这过去的三天里遇到了很多朋友,见识了很多有 ...

  5. [颓废史]蒟蒻的刷题记录

    QAQ蒟蒻一枚,其实我就是来提供水题库的. 以下记录从2016年开始. 1.1 1227: [SDOI2009]虔诚的墓主人 树状数组+离散化 3132: 上帝造题的七分钟 树状数组 二维区间加减+查 ...

  6. 2090. 「ZJOI2016」旅行者 分治,最短路

    2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+dis(g ...

  7. loj2090. 「ZJOI2016」旅行者

    loj2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+di ...

  8. 【BZOJ4016】最短路径树问题,最短路+点分治

    Time:2016.08.21 Author:xiaoyimi 转载注明出处谢谢 注意:代码中递归子树时对子树大小的计算有误,虽然可以保证正确性但是会使得求得的子树重心并不正确,可能会被卡掉 传送门 ...

  9. #41 最短路(分治+线性基)

    考虑异或最短路应该怎么求.那么这是个WC原题,dfs一遍找到所有有用的环丢进线性基即可,因为每一个环的权值都是可以取到且不对其他部分产生影响的. 现在给了一棵树,不妨就把他看做原图的dfs树.每增加一 ...

最新文章

  1. Asp.net中GridView使用详解(引)【转】
  2. MySQL中interactive_timeout和wait_timeout的区别
  3. 细数英特尔收购McAfee可获得安全产品
  4. Hough变换原始形式-直线检测
  5. rn如何测试数据请求时间_rn最新版测试
  6. C语言实现多线程排序
  7. 实例变量 成员变量 java 1615135036
  8. ROS下的多参数调用,boost::bind使用
  9. 战网下载CDN重定向失败_卧槽,又开源一个下载神器,利用各种平台下载任意文件...
  10. 基于Linux平台的libpcap源码分析和优化
  11. Oracle 10g Create Database
  12. python处理pdf的第三方库_Python使用到第三方库PyMuPDF图片与pdf相互转换
  13. 浅谈InnoDB存储引擎下锁的分类
  14. 干货|50个大数据面试问题及答案第一篇:10个大数据面试入门级问题
  15. c#自定义日历插件,给重要日期添加色彩。以及系统自带的monthCalendar日历插件
  16. arg是什么函数_JavaScript 函数式编程 - 基本范式简介
  17. 好人品的八个标准,你有几个?
  18. ESP32-C3入门教程 系统篇①——FreeRTOS系统时钟Tick
  19. 快手极速版56位 sig3
  20. Java基础面试题干货系列(一)

热门文章

  1. android 消息列表,[Android]用LinearLayout 实现类微信消息列表项
  2. ADB安卓调试工具使用总结
  3. oracle数据包对交换机要求,Exalogic Ethernet交换机配置的备份与还原
  4. 调用wasm_PDX Utopia区块链协议栈使用Solidity调用wasm智能合约
  5. (已解决)登录火狐浏览器账号后没有同步数据--博主的奇妙寻号之旅
  6. HDU 1248 寒冰王座(完全背包问题另类解法)
  7. 玩转GIT系列之【如何放弃本地/服务器端所做的修改】
  8. 探索C++的秘密之详解extern C
  9. TensorFlow调试常见问题(pycharm)
  10. pytorch线性回归_PyTorch中的线性回归