新增道路查询后的最短距离II

2024-11-20

题目:

给你一个整数 n 和一个二维整数数组 queries

n 个城市,编号从 0n - 1。初始时,每个城市 i 都有一条单向道路通往城市 i + 10 <= i < n - 1)。

queries[i] = [ui, vi] 表示新建一条从城市 ui 到城市 vi单向道路。每次查询后,你需要找到从城市 0 到城市 n - 1最短路径长度

所有查询中不会存在两个查询都满足 queries[i][0] < queries[j][0] < queries[i][1] < queries[j][1]

返回一个数组 answer,对于范围 [0, queries.length - 1] 中的每个 ianswer[i] 是处理完 i + 1 个查询后,从城市 0 到城市 n - 1 的最短路径的长度

示例 1:

输入: n = 5, queries = [[2, 4], [0, 2], [0, 4]]

输出: [3, 2, 1]

解释:

img

新增一条从 2 到 4 的道路后,从 0 到 4 的最短路径长度为 3。

img

新增一条从 0 到 2 的道路后,从 0 到 4 的最短路径长度为 2。

img

新增一条从 0 到 4 的道路后,从 0 到 4 的最短路径长度为 1。

示例 2:

输入: n = 4, queries = [[0, 3], [0, 2]]

输出: [1, 1]

解释:

img

新增一条从 0 到 3 的道路后,从 0 到 3 的最短路径长度为 1。

img

新增一条从 0 到 2 的道路后,从 0 到 3 的最短路径长度仍为 1。

提示:

  • 3 <= n <= 105
  • 1 <= queries.length <= 105
  • queries[i].length == 2
  • 0 <= queries[i][0] < queries[i][1] < n
  • 1 < queries[i][1] - queries[i][0]
  • 查询中不存在重复的道路。
  • 不存在两个查询都满足 i != jqueries[i][0] < queries[j][0] < queries[i][1] < queries[j][1]

思路:

这题跟昨天的不同点在于
	(1)新增的路径保证了不会出现交叉路径(1 -> 3, 2 -> 4),这就允许使用贪心算法,每次尽量往大的节点靠,就能保证路径最小
	(2)测试范围大量很多
	
由题意可知:
	对于任一从城市 u 到城市 v 的单向道路,都有 u < v。
	不会存在两条单向道路 [u0 ,v0] 和 [u1 ,v1],满足 u0 < u1 < v0 < v1 。将单向道路看成区间,那么任意两条单向道路要么是不相交的关系,要么是包含的关系。

基于以上两点,我们可以贪心地选择最短路径经过的单向道路。具体地,初始时所有单向道路都是互不包含的关系,那么选择所有单向道路是最优的,最短路径的长度 dist=n−1 为所有单向道路的数目。当我们新增一条单向道路时:
	如果它已经被任一现有的单向道路所包含,那么选择它不会使路径更短,直接忽略它。
	否则,我们去掉所有被新增单向道路所包含的现有单向道路,记数目为 m,然后将该新增单向道路加入最短路径中,此时最短路径的长度更新为 dist − m + 1。

具体实现上,我们可以使用 roads 表示最短路径经过的所有单向道路。roads[u]=v 表示从城市 u 到城市 v 的一条单向道路,而 roads[u] = −1 时,表示不经过城市 u(也表示以 u 起始的所有单向道路已经有对应的范围更大的单向道路)。记新增的道路为 query = [u,v]:
	如果 roads[u]=−1,那么说明选择 query 不会使路径更短,忽略它。
	否则我们不断地删除 [u,v] 之间的所有单向道路,然后将 [u,v] 加入最短路径中。

代码:

class Solution {
public:
    vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>>& queries) {
        vector<int> roads(n);
        iota(roads.begin(), roads.end(), 1);
        vector<int> res;
        int dist = n - 1;
        for (auto &query : queries) {
            int k = roads[query[0]];
            roads[query[0]] = query[1];
            while (k != -1 && k < query[1]) {
                int t = roads[k];
                roads[k] = -1;
                k = t;
                dist--;
            }
            res.push_back(dist); 
        }
        return res;
    }
};