题目传送门:LOJ #3159

题意简述:

二维平面上有 \(n\) 个整点,给定每个整点的坐标 \((x_i,y_i)\)。

有 \(m\) 种边,第 \(i\) 种边从 \(p_i\) 号点连向满足 \(l_i\le x_j\le r_i\) 和 \(d_i\le y_j\le u_i\) 的点 \(j\),即一个矩形范围内的所有点。

求 \(1\) 号点到其它每个点的最短路长度。

题解:

考虑 Dijkstra 算法求最短路的过程:

一开始只有起点的距离为 \(0\),而其它点距离为无限大。

每次取出一个距离最短的没被更新过的点,用它更新它能到达的所有未被更新过的点的距离,并将其标记为已被更新。

重复这个过程直到所有点均被更新。

上述过程一般使用单调队列来维护距离最短的点。

而在此题中,一次更新时可能加入的点会有很多很多,不能每次将其一并加入。

可以考虑加入一条边而非点,加入的这条边就代表了这条边连向的所有点的距离。

类似地,每次取出距离最短的边,此时这条边代表的矩形内部的所有点均可以进行更新,因为只会去更新未被更新过的点,所以更新完这些点的距离后,可以把这些点全部删除。

上述方法是最短路中包含“一对多”,“多对多”的边时的处理办法。还有一种方法是使用数据结构模型优化建边,但是一般不会比这种方法来得优。

至于具体如何维护矩形删点操作,删点时可以暴力一个个删除,因为每个点只会被删除一次,问题在于如何快速找到要删除的点。

这里我使用线段树套平衡树(std::set)维护,外层线段树处理横坐标上的区间,内层平衡树可以快速访问目标点将其删除。

下面是代码,时间复杂度为 \(\mathcal{O}(n\log^2n+m\log m)\):

#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <set> #define mp std::make_pair
typedef std::pair<int, int> pii;
typedef std::multiset<pii>::iterator iter;
const int MN = 70005, MM = 150005;
const int MS = 1 << 18 | 7; int N, M, W, H, yp[MN], vis[MN], dis[MN];
int h[MN], nxt[MM], et[MM], eL[MM], eR[MM], eD[MM], eU[MM];
std::multiset<pii> st[MS];
std::priority_queue<pii> pq;
void Ins(int i, int l, int r, int x, int id) {
st[i].insert(mp(yp[id], id));
if (l == r) return ;
int mid = (l + r) >> 1;
if (x <= mid) Ins(i << 1, l, mid, x, id);
else Ins(i << 1 | 1, mid + 1, r, x, id);
}
void Del(int i, int l, int r, int id, int d) {
if (r < eL[id] || eR[id] < l) return ;
if (eL[id] <= l && r <= eR[id]) {
iter it = st[i].lower_bound(mp(eD[id], 0)), tmp;
while (it != st[i].end() && it -> first <= eU[id]) {
int u = it -> second;
if (!vis[u]) {
vis[u] = 1, dis[u] = d;
for (int j = h[u]; j; j = nxt[j])
pq.push(mp(-d - et[j], j));
}
tmp = it, ++it, st[i].erase(tmp);
}
return ;
}
int mid = (l + r) >> 1;
Del(i << 1, l, mid, id, d);
Del(i << 1 | 1, mid + 1, r, id, d);
} int main() {
freopen("jump.in", "r", stdin);
freopen("jump.out", "w", stdout);
scanf("%d%d%d%d", &N, &M, &W, &H);
for (int i = 1, x; i <= N; ++i) {
scanf("%d%d", &x, &yp[i]);
Ins(1, 1, W, x, i);
}
for (int i = 1, p; i <= M; ++i) {
scanf("%d%d%d%d%d%d", &p, &et[i], &eL[i], &eR[i], &eD[i], &eU[i]);
nxt[i] = h[p], h[p] = i;
}
dis[1] = 0, vis[1] = 1;
for (int i = h[1]; i; i = nxt[i])
pq.push(mp(-et[i], i));
while (!pq.empty()) {
pii ed = pq.top(); pq.pop();
int dis = -ed.first, id = ed.second;
Del(1, 1, W, id, dis);
}
for (int i = 2; i <= N; ++i) printf("%d\n", dis[i]);
return 0;
}

最新文章

  1. SSIS Parameter用法
  2. java web学习总结(九) -------------------通过Servlet生成验证码图片
  3. coreData数据操作
  4. 使用knockout-sortable实现对自定义菜单的拖拽排序
  5. Spring+Mybatis整合报错Mapped Statements collection does not contain value原因之一
  6. HDU1026 Ignatius and the Princess I
  7. linux 常用命令 -- 系统管理工具包: 监视邮件的使用情况
  8. C#泛型理解(转)
  9. 通过ajax和spring 后台传输json数据
  10. javascript语法之Date对象与小案例
  11. 论文阅读笔记(二)U-Net
  12. 有道云笔记 - Markdown模板(文首附markdown源码,即.md文件)
  13. qrcode &amp; vue
  14. GZipStream 压缩与解压数据
  15. Pinterest凭什么拥有那么多用户:机器学习是答案
  16. Date与时间戳的相互转换(Java)
  17. ASP.NET WebApi使用Swagger生成api说明文档
  18. arachni安装使用
  19. H3C S5800 MPLS----VPLS 三层路由透传二层网络
  20. CentOS6.x服务器OpenSSH平滑升级到7.3p版本——拒绝服务器漏洞攻击

热门文章

  1. [LeetCode] 272. Closest Binary Search Tree Value II 最近的二分搜索树的值之二
  2. [LeetCode] 82. Remove Duplicates from Sorted List II 移除有序链表中的重复项之二
  3. [LeetCode] 36. Valid Sudoku 验证数独
  4. Spring Cloud Zuul记录接口响应数据
  5. oracle--DG模式备库归档缺失问题(1)
  6. PurpleAir空气质量数据采集
  7. mysql的varchar和oracle的varchar2、nvarchar2
  8. PHP服务端优化全面总结
  9. Appium+python自动化(一)- 环境搭建—上(超详解)
  10. 并行 Webclient(一)